diff options
Diffstat (limited to 'intern/audaspace/Python/AUD_PyAPI.cpp')
-rw-r--r-- | intern/audaspace/Python/AUD_PyAPI.cpp | 2973 |
1 files changed, 2973 insertions, 0 deletions
diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp new file mode 100644 index 00000000000..b0c55d5856e --- /dev/null +++ b/intern/audaspace/Python/AUD_PyAPI.cpp @@ -0,0 +1,2973 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 Jörg Hermann Müller + * + * This file is part of AudaSpace. + * + * AudaSpace is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AudaSpace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>. + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#include "AUD_PyAPI.h" +#include "structmember.h" + +#include "AUD_I3DDevice.h" +#include "AUD_NULLDevice.h" +#include "AUD_DelayFactory.h" +#include "AUD_DoubleFactory.h" +#include "AUD_FaderFactory.h" +#include "AUD_HighpassFactory.h" +#include "AUD_LimiterFactory.h" +#include "AUD_LoopFactory.h" +#include "AUD_LowpassFactory.h" +#include "AUD_PingPongFactory.h" +#include "AUD_PitchFactory.h" +#include "AUD_ReverseFactory.h" +#include "AUD_SinusFactory.h" +#include "AUD_FileFactory.h" +#include "AUD_SquareFactory.h" +#include "AUD_StreamBufferFactory.h" +#include "AUD_SuperposeFactory.h" +#include "AUD_VolumeFactory.h" +#include "AUD_IIRFilterFactory.h" + +#ifdef WITH_SDL +#include "AUD_SDLDevice.h" +#endif + +#ifdef WITH_OPENAL +#include "AUD_OpenALDevice.h" +#endif + +#ifdef WITH_JACK +#include "AUD_JackDevice.h" +#endif + +// ==================================================================== + +typedef enum +{ + AUD_DEVICE_NULL = 0, + AUD_DEVICE_OPENAL, + AUD_DEVICE_SDL, + AUD_DEVICE_JACK, + AUD_DEVICE_READ, +} AUD_DeviceTypes; + +// ==================================================================== + +#define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, #name, name) + +// ==================================================================== + +static PyObject* AUDError; + +static const char* device_not_3d_error = "Device is not a 3D device!"; + +// ==================================================================== + +static void +Factory_dealloc(Factory* self) +{ + if(self->factory) + delete self->factory; + Py_XDECREF(self->child_list); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +Factory_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Factory *self; + + self = (Factory*)type->tp_alloc(type, 0); + if(self != NULL) + { + static const char *kwlist[] = {"filename", NULL}; + const char* filename = NULL; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "s:Factory", const_cast<char**>(kwlist), &filename)) + { + Py_DECREF(self); + return NULL; + } + + try + { + self->factory = new AUD_FileFactory(filename); + } + catch(AUD_Exception& e) + { + Py_DECREF(self); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)self; +} + +PyDoc_STRVAR(M_aud_Factory_sine_doc, + "sine(frequency, rate=44100)\n\n" + "Creates a sine factory 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:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_sine(PyTypeObject* type, PyObject* args) +{ + float frequency; + int rate = 44100; + + if(!PyArg_ParseTuple(args, "f|i:sine", &frequency, &rate)) + return NULL; + + Factory *self; + + self = (Factory*)type->tp_alloc(type, 0); + if(self != NULL) + { + try + { + self->factory = new AUD_SinusFactory(frequency, (AUD_SampleRate)rate); + } + catch(AUD_Exception& e) + { + Py_DECREF(self); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)self; +} + +PyDoc_STRVAR(M_aud_Factory_file_doc, + "file(filename)\n\n" + "Creates a factory object of a sound file.\n\n" + ":arg filename: Path of the file.\n" + ":type filename: string\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\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 factory."); + +static PyObject * +Factory_file(PyTypeObject* type, PyObject* args) +{ + const char* filename = NULL; + + if(!PyArg_ParseTuple(args, "s:file", &filename)) + return NULL; + + Factory *self; + + self = (Factory*)type->tp_alloc(type, 0); + if(self != NULL) + { + try + { + self->factory = new AUD_FileFactory(filename); + } + catch(AUD_Exception& e) + { + Py_DECREF(self); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)self; +} + +PyDoc_STRVAR(M_aud_Factory_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:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_lowpass(Factory* self, PyObject* args) +{ + float frequency; + float Q = 0.5; + + if(!PyArg_ParseTuple(args, "f|f:lowpass", &frequency, &Q)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_LowpassFactory(self->factory, frequency, Q); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_delay_doc, + "delay(time)\n\n" + "Delays by playing adding silence in front of the other factory's " + "data.\n\n" + ":arg time: How many seconds of silence should be added before " + "the factory.\n" + ":type time: float\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_delay(Factory* self, PyObject* args) +{ + float delay; + + if(!PyArg_ParseTuple(args, "f:delay", &delay)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_DelayFactory(self->factory, delay); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_join_doc, + "join(factory)\n\n" + "Plays two factories in sequence.\n\n" + ":arg factory: The factory to play second.\n" + ":type factory: :class:`Factory`\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: The two factories have to have the same specifications " + "(channels and samplerate)."); + +static PyObject * +Factory_join(Factory* self, PyObject* object) +{ + PyTypeObject* type = ((PyObject*)self)->ob_type; + + if(!PyObject_TypeCheck(object, type)) + { + PyErr_SetString(PyExc_TypeError, "Object has to be of type Factory!"); + return NULL; + } + + Factory *parent; + Factory *child = (Factory*)object; + + parent = (Factory*)type->tp_alloc(type, 0); + if(parent != NULL) + { + parent->child_list = Py_BuildValue("(OO)", self, object); + + try + { + parent->factory = new AUD_DoubleFactory(self->factory, child->factory); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_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:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_highpass(Factory* self, PyObject* args) +{ + float frequency; + float Q = 0.5; + + if(!PyArg_ParseTuple(args, "f|f:highpass", &frequency, &Q)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_HighpassFactory(self->factory, frequency, Q); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_limit_doc, + "limit(start, end)\n\n" + "Limits a factory 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:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_limit(Factory* self, PyObject* args) +{ + float start, end; + + if(!PyArg_ParseTuple(args, "ff:limit", &start, &end)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_LimiterFactory(self->factory, start, end); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_pitch_doc, + "pitch(factor)\n\n" + "Changes the pitch of a factory with a specific factor.\n\n" + ":arg factor: The factor to change the pitch with.\n" + ":type factor: float\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: This is done by changing the sample rate of the " + "underlying factory, 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 * +Factory_pitch(Factory* self, PyObject* args) +{ + float factor; + + if(!PyArg_ParseTuple(args, "f:pitch", &factor)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_PitchFactory(self->factory, factor); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_volume_doc, + "volume(volume)\n\n" + "Changes the volume of a factory.\n\n" + ":arg volume: The new volume..\n" + ":type volume: float\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\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 * +Factory_volume(Factory* self, PyObject* args) +{ + float volume; + + if(!PyArg_ParseTuple(args, "f:volume", &volume)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_VolumeFactory(self->factory, volume); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_fadein_doc, + "fadein(start, length)\n\n" + "Fades a factory 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:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: Before the fade starts it plays silence."); + +static PyObject * +Factory_fadein(Factory* self, PyObject* args) +{ + float start, length; + + if(!PyArg_ParseTuple(args, "ff:fadein", &start, &length)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_FaderFactory(self->factory, AUD_FADE_IN, start, length); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_fadeout_doc, + "fadeout(start, length)\n\n" + "Fades a factory 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:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: After the fade this factory plays silence, so that " + "the length of the factory is not altered."); + +static PyObject * +Factory_fadeout(Factory* self, PyObject* args) +{ + float start, length; + + if(!PyArg_ParseTuple(args, "ff:fadeout", &start, &length)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_FaderFactory(self->factory, AUD_FADE_OUT, start, length); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_loop_doc, + "loop(count)\n\n" + "Loops a factory.\n\n" + ":arg count: How often the factory should be looped. " + "Negative values mean endlessly.\n" + ":type count: integer\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: This is a filter function, you might consider using " + ":attr:`Handle.loop_count` instead."); + +static PyObject * +Factory_loop(Factory* self, PyObject* args) +{ + int loop; + + if(!PyArg_ParseTuple(args, "i:loop", &loop)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_LoopFactory(self->factory, loop); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_mix_doc, + "mix(factory)\n\n" + "Mixes two factories.\n\n" + ":arg factory: The factory to mix over the other.\n" + ":type factory: :class:`Factory`\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: The two factories have to have the same specifications " + "(channels and samplerate)."); + +static PyObject * +Factory_mix(Factory* self, PyObject* object) +{ + PyTypeObject* type = ((PyObject*)self)->ob_type; + + if(!PyObject_TypeCheck(object, type)) + { + PyErr_SetString(PyExc_TypeError, "Object is not of type Factory!"); + return NULL; + } + + Factory *parent = (Factory*)type->tp_alloc(type, 0); + Factory *child = (Factory*)object; + + if(parent != NULL) + { + parent->child_list = Py_BuildValue("(OO)", self, object); + + try + { + parent->factory = new AUD_SuperposeFactory(self->factory, child->factory); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_pingpong_doc, + "pingpong()\n\n" + "Plays a factory forward and then backward.\n" + "This is like joining a factory with its reverse.\n\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_pingpong(Factory* self) +{ + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_PingPongFactory(self->factory); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_reverse_doc, + "reverse()\n\n" + "Plays a factory reversed.\n\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\n\n" + ".. note:: The factory 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:`buffer` before " + "being played reversed.\n\n" + ".. warning:: If seeking is not accurate in the underlying factory " + "you'll likely hear skips/jumps/cracks."); + +static PyObject * +Factory_reverse(Factory* self) +{ + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_ReverseFactory(self->factory); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_buffer_doc, + "buffer()\n\n" + "Buffers a factory into RAM.\n" + "This saves CPU usage needed for decoding and file access if the " + "underlying factory reads from a file on the harddisk, but it " + "consumes a lot of memory.\n\n" + ":return: The created :class:`Factory` object.\n" + ":rtype: :class:`Factory`\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 * +Factory_buffer(Factory* self) +{ + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + try + { + parent->factory = new AUD_StreamBufferFactory(self->factory); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_square_doc, + "square(threshold = 0)\n\n" + "Makes a square 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:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_square(Factory* self, PyObject* args) +{ + float threshold = 0; + + if(!PyArg_ParseTuple(args, "|f:square", &threshold)) + return NULL; + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_SquareFactory(self->factory, threshold); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +PyDoc_STRVAR(M_aud_Factory_filter_doc, + "filter(b, a = (1))\n\n" + "Filters a factory 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:`Factory` object.\n" + ":rtype: :class:`Factory`"); + +static PyObject * +Factory_filter(Factory* self, PyObject* args) +{ + PyObject* py_b; + PyObject* py_a = NULL; + + if(!PyArg_ParseTuple(args, "O|O:filter", &py_b, &py_a)) + return NULL; + + if(!PySequence_Check(py_b) || (py_a != NULL && !PySequence_Check(py_a))) + { + PyErr_SetString(PyExc_TypeError, "Parameter is not a sequence!"); + return NULL; + } + + if(!PySequence_Length(py_b) || (py_a != NULL && !PySequence_Length(py_a))) + { + PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!"); + return NULL; + } + + std::vector<float> a, b; + PyObject* py_value; + float value; + int result; + + for(int i = 0; i < PySequence_Length(py_b); i++) + { + py_value = PySequence_GetItem(py_b, i); + result = PyArg_Parse(py_value, "f:filter", &value); + Py_DECREF(py_value); + + if(!result) + return NULL; + + b.push_back(value); + } + + if(py_a) + { + for(int i = 0; i < PySequence_Length(py_a); i++) + { + py_value = PySequence_GetItem(py_a, i); + result = PyArg_Parse(py_value, "f:filter", &value); + Py_DECREF(py_value); + + if(!result) + return NULL; + + a.push_back(value); + } + + if(a[0] == 0) + a[0] = 1; + } + else + a.push_back(1); + + PyTypeObject* type = ((PyObject*)self)->ob_type; + Factory *parent = (Factory*)type->tp_alloc(type, 0); + + if(parent != NULL) + { + Py_INCREF(self); + parent->child_list = (PyObject*)self; + + try + { + parent->factory = new AUD_IIRFilterFactory(self->factory, b, a); + } + catch(AUD_Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)parent; +} + +static PyMethodDef Factory_methods[] = { + {"sine", (PyCFunction)Factory_sine, METH_VARARGS | METH_CLASS, + M_aud_Factory_sine_doc + }, + {"file", (PyCFunction)Factory_file, METH_VARARGS | METH_CLASS, + M_aud_Factory_file_doc + }, + {"lowpass", (PyCFunction)Factory_lowpass, METH_VARARGS, + M_aud_Factory_lowpass_doc + }, + {"delay", (PyCFunction)Factory_delay, METH_VARARGS, + M_aud_Factory_delay_doc + }, + {"join", (PyCFunction)Factory_join, METH_O, + M_aud_Factory_join_doc + }, + {"highpass", (PyCFunction)Factory_highpass, METH_VARARGS, + M_aud_Factory_highpass_doc + }, + {"limit", (PyCFunction)Factory_limit, METH_VARARGS, + M_aud_Factory_limit_doc + }, + {"pitch", (PyCFunction)Factory_pitch, METH_VARARGS, + M_aud_Factory_pitch_doc + }, + {"volume", (PyCFunction)Factory_volume, METH_VARARGS, + M_aud_Factory_volume_doc + }, + {"fadein", (PyCFunction)Factory_fadein, METH_VARARGS, + M_aud_Factory_fadein_doc + }, + {"fadeout", (PyCFunction)Factory_fadeout, METH_VARARGS, + M_aud_Factory_fadeout_doc + }, + {"loop", (PyCFunction)Factory_loop, METH_VARARGS, + M_aud_Factory_loop_doc + }, + {"mix", (PyCFunction)Factory_mix, METH_O, + M_aud_Factory_mix_doc + }, + {"pingpong", (PyCFunction)Factory_pingpong, METH_NOARGS, + M_aud_Factory_pingpong_doc + }, + {"reverse", (PyCFunction)Factory_reverse, METH_NOARGS, + M_aud_Factory_reverse_doc + }, + {"buffer", (PyCFunction)Factory_buffer, METH_NOARGS, + M_aud_Factory_buffer_doc + }, + {"square", (PyCFunction)Factory_square, METH_VARARGS, + M_aud_Factory_square_doc + }, + {"filter", (PyCFunction)Factory_filter, METH_VARARGS, + M_aud_Factory_filter_doc + }, + {NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(M_aud_Factory_doc, + "Factory 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."); + +static PyTypeObject FactoryType = { + PyVarObject_HEAD_INIT(NULL, 0) + "aud.Factory", /* tp_name */ + sizeof(Factory), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Factory_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_Factory_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Factory_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* 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 */ + Factory_new, /* tp_new */ +}; + +// ========== Handle ================================================== + +static void +Handle_dealloc(Handle* self) +{ + Py_XDECREF(self->device); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(M_aud_Handle_pause_doc, + "pause()\n\n" + "Pauses playback.\n\n" + ":return: Whether the action succeeded.\n" + ":rtype: bool"); + +static PyObject * +Handle_pause(Handle *self) +{ + Device* device = (Device*)self->device; + + try + { + if(device->device->pause(self->handle)) + { + Py_RETURN_TRUE; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } + + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(M_aud_Handle_resume_doc, + "resume()\n\n" + "Resumes playback.\n\n" + ":return: Whether the action succeeded.\n" + ":rtype: bool"); + +static PyObject * +Handle_resume(Handle *self) +{ + Device* device = (Device*)self->device; + + try + { + if(device->device->resume(self->handle)) + { + Py_RETURN_TRUE; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } + + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(M_aud_Handle_stop_doc, + "stop()\n\n" + "Stops playback.\n\n" + ":return: Whether the action succeeded.\n" + ":rtype: bool\n\n" + ".. note:: This makes the handle invalid."); + +static PyObject * +Handle_stop(Handle *self) +{ + Device* device = (Device*)self->device; + + try + { + if(device->device->stop(self->handle)) + { + Py_RETURN_TRUE; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } + + Py_RETURN_FALSE; +} + +static PyMethodDef Handle_methods[] = { + {"pause", (PyCFunction)Handle_pause, METH_NOARGS, + M_aud_Handle_pause_doc + }, + {"resume", (PyCFunction)Handle_resume, METH_NOARGS, + M_aud_Handle_resume_doc + }, + {"stop", (PyCFunction)Handle_stop, METH_NOARGS, + M_aud_Handle_stop_doc + }, + {NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(M_aud_Handle_position_doc, + "The playback position of the sound in seconds."); + +static PyObject * +Handle_get_position(Handle *self, void* nothing) +{ + Device* device = (Device*)self->device; + + try + { + return Py_BuildValue("f", device->device->getPosition(self->handle)); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_position(Handle *self, PyObject* args, void* nothing) +{ + float position; + + if(!PyArg_Parse(args, "f:position", &position)) + return -1; + + Device* device = (Device*)self->device; + + try + { + if(device->device->seek(self->handle, position)) + return 0; + PyErr_SetString(AUDError, "Couldn't seek the sound!"); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_keep_doc, + "Whether the sound should be kept paused in the device when its " + "end is reached.\n" + "This can be used to seek the sound to some position and start " + "playback again.\n\n" + ".. warning:: If this is set to true and you forget stopping this " + "equals a memory leak as the handle exists until the device is " + "destroyed."); + +static PyObject * +Handle_get_keep(Handle *self, void* nothing) +{ + Device* device = (Device*)self->device; + + try + { + if(device->device->getKeep(self->handle)) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_keep(Handle *self, PyObject* args, void* nothing) +{ + if(!PyBool_Check(args)) + { + PyErr_SetString(PyExc_TypeError, "keep is not a boolean!"); + return -1; + } + + bool keep = args == Py_True; + Device* device = (Device*)self->device; + + try + { + if(device->device->setKeep(self->handle, keep)) + return 0; + PyErr_SetString(AUDError, "Couldn't set keep of the sound!"); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_status_doc, + "Whether the sound is playing, paused or stopped (=invalid)."); + +static PyObject * +Handle_get_status(Handle *self, void* nothing) +{ + Device* device = (Device*)self->device; + + try + { + return Py_BuildValue("i", device->device->getStatus(self->handle)); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +PyDoc_STRVAR(M_aud_Handle_volume_doc, + "The volume of the sound."); + +static PyObject * +Handle_get_volume(Handle *self, void* nothing) +{ + Device* device = (Device*)self->device; + + try + { + return Py_BuildValue("f", device->device->getVolume(self->handle)); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_volume(Handle *self, PyObject* args, void* nothing) +{ + float volume; + + if(!PyArg_Parse(args, "f:volume", &volume)) + return -1; + + Device* device = (Device*)self->device; + + try + { + if(device->device->setVolume(self->handle, volume)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the sound volume!"); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_pitch_doc, + "The pitch of the sound."); + +static PyObject * +Handle_get_pitch(Handle *self, void* nothing) +{ + Device* device = (Device*)self->device; + + try + { + return Py_BuildValue("f", device->device->getPitch(self->handle)); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_pitch(Handle *self, PyObject* args, void* nothing) +{ + float pitch; + + if(!PyArg_Parse(args, "f:pitch", &pitch)) + return -1; + + Device* device = (Device*)self->device; + + try + { + if(device->device->setPitch(self->handle, pitch)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the sound pitch!"); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_loop_count_doc, + "The (remaining) loop count of the sound. A negative value indicates infinity."); + +static PyObject * +Handle_get_loop_count(Handle *self, void* nothing) +{ + Device* device = (Device*)self->device; + + try + { + return Py_BuildValue("i", device->device->getLoopCount(self->handle)); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_loop_count(Handle *self, PyObject* args, void* nothing) +{ + int loops; + + if(!PyArg_Parse(args, "i:loop_count", &loops)) + return -1; + + Device* device = (Device*)self->device; + + try + { + if(device->device->setLoopCount(self->handle, loops)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the loop count!"); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_location_doc, + "The source's location in 3D space, a 3D tuple of floats."); + +static PyObject * +Handle_get_location(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + AUD_Vector3 v = device->getSourceLocation(self->handle); + return Py_BuildValue("(fff)", v.x(), v.y(), v.z()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Handle_set_location(Handle *self, PyObject* args, void* nothing) +{ + float x, y, z; + + if(!PyArg_Parse(args, "(fff):location", &x, &y, &z)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + AUD_Vector3 location(x, y, z); + if(device->setSourceLocation(self->handle, location)) + return 0; + PyErr_SetString(AUDError, "Location couldn't be set!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_velocity_doc, + "The source's velocity in 3D space, a 3D tuple of floats."); + +static PyObject * +Handle_get_velocity(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + AUD_Vector3 v = device->getSourceVelocity(self->handle); + return Py_BuildValue("(fff)", v.x(), v.y(), v.z()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Handle_set_velocity(Handle *self, PyObject* args, void* nothing) +{ + float x, y, z; + + if(!PyArg_Parse(args, "(fff):velocity", &x, &y, &z)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + AUD_Vector3 velocity(x, y, z); + if(device->setSourceVelocity(self->handle, velocity)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the velocity!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_orientation_doc, + "The source's orientation in 3D space as quaternion, a 4 float tuple."); + +static PyObject * +Handle_get_orientation(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + AUD_Quaternion o = device->getSourceOrientation(self->handle); + return Py_BuildValue("(ffff)", o.w(), o.x(), o.y(), o.z()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Handle_set_orientation(Handle *self, PyObject* args, void* nothing) +{ + float w, x, y, z; + + if(!PyArg_Parse(args, "(ffff):orientation", &w, &x, &y, &z)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + AUD_Quaternion orientation(w, x, y, z); + if(device->setSourceOrientation(self->handle, orientation)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the orientation!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_relative_doc, + "Whether the source's location, velocity and orientation is relative or absolute to the listener."); + +static PyObject * +Handle_get_relative(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->isRelative(self->handle)) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Handle_set_relative(Handle *self, PyObject* args, void* nothing) +{ + if(!PyBool_Check(args)) + { + PyErr_SetString(PyExc_TypeError, "Value is not a boolean!"); + return -1; + } + + bool relative = (args == Py_True); + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setRelative(self->handle, relative)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the relativeness!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_volume_minimum_doc, + "The minimum volume of the source.\n\n" + ".. seealso:: :attr:`Device.distance_model`"); + +static PyObject * +Handle_get_volume_minimum(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getVolumeMinimum(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_volume_minimum(Handle *self, PyObject* args, void* nothing) +{ + float volume; + + if(!PyArg_Parse(args, "f:volume_minimum", &volume)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setVolumeMinimum(self->handle, volume)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the minimum volume!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_volume_maximum_doc, + "The maximum volume of the source.\n\n" + ".. seealso:: :attr:`Device.distance_model`"); + +static PyObject * +Handle_get_volume_maximum(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getVolumeMaximum(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_volume_maximum(Handle *self, PyObject* args, void* nothing) +{ + float volume; + + if(!PyArg_Parse(args, "f:volume_maximum", &volume)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setVolumeMaximum(self->handle, volume)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the maximum volume!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_distance_reference_doc, + "The reference distance of the source.\n" + "At this distance the volume will be exactly :attr:`volume`.\n\n" + ".. seealso:: :attr:`Device.distance_model`"); + +static PyObject * +Handle_get_distance_reference(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getDistanceReference(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_distance_reference(Handle *self, PyObject* args, void* nothing) +{ + float distance; + + if(!PyArg_Parse(args, "f:distance_reference", &distance)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setDistanceReference(self->handle, distance)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the reference distance!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_distance_maximum_doc, + "The maximum distance of the source.\n" + "If the listener is further away the source volume will be 0.\n\n" + ".. seealso:: :attr:`Device.distance_model`"); + +static PyObject * +Handle_get_distance_maximum(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getDistanceMaximum(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_distance_maximum(Handle *self, PyObject* args, void* nothing) +{ + float distance; + + if(!PyArg_Parse(args, "f:distance_maximum", &distance)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setDistanceMaximum(self->handle, distance)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the maximum distance!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_attenuation_doc, + "This factor is used for distance based attenuation of the " + "source.\n\n" + ".. seealso:: :attr:`Device.distance_model`"); + +static PyObject * +Handle_get_attenuation(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getAttenuation(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_attenuation(Handle *self, PyObject* args, void* nothing) +{ + float factor; + + if(!PyArg_Parse(args, "f:attenuation", &factor)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setAttenuation(self->handle, factor)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the attenuation!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_cone_angle_inner_doc, + "The opening angle of the inner cone of the source. If the cone " + "values of a source are set there are two (audible) cones with " + "the apex at the :attr:`location` of the source and with infinite " + "height, heading in the direction of the source's " + ":attr:`orientation`.\n" + "In the inner cone the volume is normal. Outside the outer cone " + "the volume will be :attr:`cone_volume_outer` and in the area " + "between the volume will be interpolated linearly."); + +static PyObject * +Handle_get_cone_angle_inner(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getConeAngleInner(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_cone_angle_inner(Handle *self, PyObject* args, void* nothing) +{ + float angle; + + if(!PyArg_Parse(args, "f:cone_angle_inner", &angle)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setConeAngleInner(self->handle, angle)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the cone inner angle!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_cone_angle_outer_doc, + "The opening angle of the outer cone of the source.\n\n" + ".. seealso:: :attr:`cone_angle_inner`"); + +static PyObject * +Handle_get_cone_angle_outer(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getConeAngleOuter(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_cone_angle_outer(Handle *self, PyObject* args, void* nothing) +{ + float angle; + + if(!PyArg_Parse(args, "f:cone_angle_outer", &angle)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setConeAngleOuter(self->handle, angle)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the cone outer angle!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Handle_cone_volume_outer_doc, + "The volume outside the outer cone of the source.\n\n" + ".. seealso:: :attr:`cone_angle_inner`"); + +static PyObject * +Handle_get_cone_volume_outer(Handle *self, void* nothing) +{ + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + return Py_BuildValue("f", device->getConeVolumeOuter(self->handle)); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Handle_set_cone_volume_outer(Handle *self, PyObject* args, void* nothing) +{ + float volume; + + if(!PyArg_Parse(args, "f:cone_volume_outer", &volume)) + return -1; + + Device* dev = (Device*)self->device; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(dev->device); + if(device) + { + if(device->setConeVolumeOuter(self->handle, volume)) + return 0; + PyErr_SetString(AUDError, "Couldn't set the cone outer volume!"); + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +static PyGetSetDef Handle_properties[] = { + {(char*)"position", (getter)Handle_get_position, (setter)Handle_set_position, + M_aud_Handle_position_doc, NULL }, + {(char*)"keep", (getter)Handle_get_keep, (setter)Handle_set_keep, + M_aud_Handle_keep_doc, NULL }, + {(char*)"status", (getter)Handle_get_status, NULL, + M_aud_Handle_status_doc, NULL }, + {(char*)"volume", (getter)Handle_get_volume, (setter)Handle_set_volume, + M_aud_Handle_volume_doc, NULL }, + {(char*)"pitch", (getter)Handle_get_pitch, (setter)Handle_set_pitch, + M_aud_Handle_pitch_doc, NULL }, + {(char*)"loop_count", (getter)Handle_get_loop_count, (setter)Handle_set_loop_count, + M_aud_Handle_loop_count_doc, NULL }, + {(char*)"location", (getter)Handle_get_location, (setter)Handle_set_location, + M_aud_Handle_location_doc, NULL }, + {(char*)"velocity", (getter)Handle_get_velocity, (setter)Handle_set_velocity, + M_aud_Handle_velocity_doc, NULL }, + {(char*)"orientation", (getter)Handle_get_orientation, (setter)Handle_set_orientation, + M_aud_Handle_orientation_doc, NULL }, + {(char*)"relative", (getter)Handle_get_relative, (setter)Handle_set_relative, + M_aud_Handle_relative_doc, NULL }, + {(char*)"volume_minimum", (getter)Handle_get_volume_minimum, (setter)Handle_set_volume_minimum, + M_aud_Handle_volume_minimum_doc, NULL }, + {(char*)"volume_maximum", (getter)Handle_get_volume_maximum, (setter)Handle_set_volume_maximum, + M_aud_Handle_volume_maximum_doc, NULL }, + {(char*)"distance_reference", (getter)Handle_get_distance_reference, (setter)Handle_set_distance_reference, + M_aud_Handle_distance_reference_doc, NULL }, + {(char*)"distance_maximum", (getter)Handle_get_distance_maximum, (setter)Handle_set_distance_maximum, + M_aud_Handle_distance_maximum_doc, NULL }, + {(char*)"attenuation", (getter)Handle_get_attenuation, (setter)Handle_set_attenuation, + M_aud_Handle_attenuation_doc, NULL }, + {(char*)"cone_angle_inner", (getter)Handle_get_cone_angle_inner, (setter)Handle_set_cone_angle_inner, + M_aud_Handle_cone_angle_inner_doc, NULL }, + {(char*)"cone_angle_outer", (getter)Handle_get_cone_angle_outer, (setter)Handle_set_cone_angle_outer, + M_aud_Handle_cone_angle_outer_doc, NULL }, + {(char*)"cone_volume_outer", (getter)Handle_get_cone_volume_outer, (setter)Handle_set_cone_volume_outer, + M_aud_Handle_cone_volume_outer_doc, NULL }, + {NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(M_aud_Handle_doc, + "Handle objects are playback handles that can be used to control " + "playback of a sound. If a sound is played back multiple times " + "then there are as many handles."); + +static PyTypeObject HandleType = { + PyVarObject_HEAD_INIT(NULL, 0) + "aud.Handle", /* tp_name */ + sizeof(Handle), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Handle_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_Handle_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Handle_methods, /* tp_methods */ + 0, /* tp_members */ + Handle_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 */ + 0, /* tp_new */ +}; + +// ========== Device ================================================== + +static void +Device_dealloc(Device* self) +{ + if(self->device) + delete self->device; + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +Device_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Device *self; + + static const char *kwlist[] = {"type", "rate", "channels", "format", "buffer_size", "name", NULL}; + int device; + int rate = AUD_RATE_44100; + int channels = AUD_CHANNELS_STEREO; + int format = AUD_FORMAT_FLOAT32; + int buffersize = AUD_DEFAULT_BUFFER_SIZE; + const char* name = "Audaspace"; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "i|iiiis:Device", const_cast<char**>(kwlist), + &device, &rate, &channels, &format, &buffersize, &name)) + return NULL; + + if(buffersize < 128) + { + PyErr_SetString(PyExc_ValueError, "buffer_size must be greater than 127!"); + return NULL; + } + + self = (Device*)type->tp_alloc(type, 0); + if(self != NULL) + { + AUD_DeviceSpecs specs; + specs.channels = (AUD_Channels)channels; + specs.format = (AUD_SampleFormat)format; + specs.rate = (AUD_SampleRate)rate; + + self->device = NULL; + + try + { + switch(device) + { + case AUD_DEVICE_NULL: + self->device = new AUD_NULLDevice(); + break; + case AUD_DEVICE_OPENAL: +#ifdef WITH_OPENAL + self->device = new AUD_OpenALDevice(specs, buffersize); +#endif + break; + case AUD_DEVICE_SDL: +#ifdef WITH_SDL + self->device = new AUD_SDLDevice(specs, buffersize); +#endif + break; + case AUD_DEVICE_JACK: +#ifdef WITH_JACK + self->device = new AUD_JackDevice(name, specs, buffersize); +#endif + break; + case AUD_DEVICE_READ: + break; + } + + } + catch(AUD_Exception& e) + { + Py_DECREF(self); + PyErr_SetString(AUDError, e.str); + return NULL; + } + + if(!self->device) + { + Py_DECREF(self); + PyErr_SetString(AUDError, "Unsupported device type!"); + return NULL; + } + } + + return (PyObject *)self; +} + +PyDoc_STRVAR(M_aud_Device_play_doc, + "play(factory, keep=False)\n\n" + "Plays a factory.\n\n" + ":arg factory: The factory to play.\n" + ":type factory: :class:`Factory`\n" + ":arg keep: See :attr:`Handle.keep`.\n" + ":type keep: bool\n" + ":return: The playback handle with which playback can be " + "controlled with.\n" + ":rtype: :class:`Handle`"); + +static PyObject * +Device_play(Device *self, PyObject *args, PyObject *kwds) +{ + PyObject* object; + PyObject* keepo = NULL; + + bool keep = false; + + static const char *kwlist[] = {"factory", "keep", NULL}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:play", const_cast<char**>(kwlist), &object, &keepo)) + return NULL; + + if(!PyObject_TypeCheck(object, &FactoryType)) + { + PyErr_SetString(PyExc_TypeError, "Object is not of type Factory!"); + return NULL; + } + + if(keepo != NULL) + { + if(!PyBool_Check(keepo)) + { + PyErr_SetString(PyExc_TypeError, "keep is not a boolean!"); + return NULL; + } + + keep = keepo == Py_True; + } + + Factory* sound = (Factory*)object; + Handle *handle; + + handle = (Handle*)HandleType.tp_alloc(&HandleType, 0); + if(handle != NULL) + { + handle->device = (PyObject*)self; + Py_INCREF(self); + + try + { + handle->handle = self->device->play(sound->factory, keep); + } + catch(AUD_Exception& e) + { + Py_DECREF(handle); + PyErr_SetString(AUDError, e.str); + return NULL; + } + } + + return (PyObject *)handle; +} + +PyDoc_STRVAR(M_aud_Device_lock_doc, + "lock()\n\n" + "Locks the device so that it's guaranteed, that no samples are " + "read from the streams until :meth:`unlock` is called.\n" + "This is useful if you want to do start/stop/pause/resume some " + "sounds at the same time.\n\n" + ".. note:: The device has to be unlocked as often as locked to be " + "able to continue playback.\n\n" + ".. warning:: Make sure the time between locking and unlocking is " + "as short as possible to avoid clicks."); + +static PyObject * +Device_lock(Device *self) +{ + try + { + self->device->lock(); + Py_RETURN_NONE; + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +PyDoc_STRVAR(M_aud_Device_unlock_doc, + "unlock()\n\n" + "Unlocks the device after a lock call, see :meth:`lock` for " + "details."); + +static PyObject * +Device_unlock(Device *self) +{ + try + { + self->device->unlock(); + Py_RETURN_NONE; + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static PyMethodDef Device_methods[] = { + {"play", (PyCFunction)Device_play, METH_VARARGS | METH_KEYWORDS, + M_aud_Device_play_doc + }, + {"lock", (PyCFunction)Device_lock, METH_NOARGS, + M_aud_Device_lock_doc + }, + {"unlock", (PyCFunction)Device_unlock, METH_NOARGS, + M_aud_Device_unlock_doc + }, + {NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(M_aud_Device_rate_doc, + "The sampling rate of the device in Hz."); + +static PyObject * +Device_get_rate(Device *self, void* nothing) +{ + try + { + AUD_DeviceSpecs specs = self->device->getSpecs(); + return Py_BuildValue("i", specs.rate); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +PyDoc_STRVAR(M_aud_Device_format_doc, + "The native sample format of the device."); + +static PyObject * +Device_get_format(Device *self, void* nothing) +{ + try + { + AUD_DeviceSpecs specs = self->device->getSpecs(); + return Py_BuildValue("i", specs.format); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +PyDoc_STRVAR(M_aud_Device_channels_doc, + "The channel count of the device."); + +static PyObject * +Device_get_channels(Device *self, void* nothing) +{ + try + { + AUD_DeviceSpecs specs = self->device->getSpecs(); + return Py_BuildValue("i", specs.channels); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +PyDoc_STRVAR(M_aud_Device_volume_doc, + "The overall volume of the device."); + +static PyObject * +Device_get_volume(Device *self, void* nothing) +{ + try + { + return Py_BuildValue("f", self->device->getVolume()); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Device_set_volume(Device *self, PyObject* args, void* nothing) +{ + float volume; + + if(!PyArg_Parse(args, "f:volume", &volume)) + return -1; + + try + { + self->device->setVolume(volume); + return 0; + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return -1; + } +} + +PyDoc_STRVAR(M_aud_Device_listener_location_doc, + "The listeners's location in 3D space, a 3D tuple of floats."); + +static PyObject * +Device_get_listener_location(Device *self, void* nothing) +{ + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + AUD_Vector3 v = device->getListenerLocation(); + return Py_BuildValue("(fff)", v.x(), v.y(), v.z()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Device_set_listener_location(Device *self, PyObject* args, void* nothing) +{ + float x, y, z; + + if(!PyArg_Parse(args, "(fff):listener_location", &x, &y, &z)) + return -1; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + AUD_Vector3 location(x, y, z); + device->setListenerLocation(location); + return 0; + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Device_listener_velocity_doc, + "The listener's velocity in 3D space, a 3D tuple of floats."); + +static PyObject * +Device_get_listener_velocity(Device *self, void* nothing) +{ + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + AUD_Vector3 v = device->getListenerVelocity(); + return Py_BuildValue("(fff)", v.x(), v.y(), v.z()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Device_set_listener_velocity(Device *self, PyObject* args, void* nothing) +{ + float x, y, z; + + if(!PyArg_Parse(args, "(fff):listener_velocity", &x, &y, &z)) + return -1; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + AUD_Vector3 velocity(x, y, z); + device->setListenerVelocity(velocity); + return 0; + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Device_listener_orientation_doc, + "The listener's orientation in 3D space as quaternion, a 4 float tuple."); + +static PyObject * +Device_get_listener_orientation(Device *self, void* nothing) +{ + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + AUD_Quaternion o = device->getListenerOrientation(); + return Py_BuildValue("(ffff)", o.w(), o.x(), o.y(), o.z()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return NULL; +} + +static int +Device_set_listener_orientation(Device *self, PyObject* args, void* nothing) +{ + float w, x, y, z; + + if(!PyArg_Parse(args, "(ffff):listener_orientation", &w, &x, &y, &z)) + return -1; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + AUD_Quaternion orientation(w, x, y, z); + device->setListenerOrientation(orientation); + return 0; + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Device_speed_of_sound_doc, + "The speed of sound of the device.\n" + "The speed of sound in air is typically 343 m/s."); + +static PyObject * +Device_get_speed_of_sound(Device *self, void* nothing) +{ + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + return Py_BuildValue("f", device->getSpeedOfSound()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Device_set_speed_of_sound(Device *self, PyObject* args, void* nothing) +{ + float speed; + + if(!PyArg_Parse(args, "f:speed_of_sound", &speed)) + return -1; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + device->setSpeedOfSound(speed); + return 0; + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Device_doppler_factor_doc, + "The doppler factor of the device.\n" + "This factor is a scaling factor for the velocity vectors in " + "doppler calculation. So a value bigger than 1 will exaggerate " + "the effect as it raises the velocity."); + +static PyObject * +Device_get_doppler_factor(Device *self, void* nothing) +{ + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + return Py_BuildValue("f", device->getDopplerFactor()); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Device_set_doppler_factor(Device *self, PyObject* args, void* nothing) +{ + float factor; + + if(!PyArg_Parse(args, "f:doppler_factor", &factor)) + return -1; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + device->setDopplerFactor(factor); + return 0; + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +PyDoc_STRVAR(M_aud_Device_distance_model_doc, + "The distance model of the device.\n\n" + ".. seealso:: http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm#_Toc199835864"); + +static PyObject * +Device_get_distance_model(Device *self, void* nothing) +{ + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + return Py_BuildValue("i", int(device->getDistanceModel())); + } + else + { + PyErr_SetString(AUDError, device_not_3d_error); + return NULL; + } + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + return NULL; + } +} + +static int +Device_set_distance_model(Device *self, PyObject* args, void* nothing) +{ + int model; + + if(!PyArg_Parse(args, "i:distance_model", &model)) + return -1; + + try + { + AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(self->device); + if(device) + { + device->setDistanceModel(AUD_DistanceModel(model)); + return 0; + } + else + PyErr_SetString(AUDError, device_not_3d_error); + } + catch(AUD_Exception& e) + { + PyErr_SetString(AUDError, e.str); + } + + return -1; +} + +static PyGetSetDef Device_properties[] = { + {(char*)"rate", (getter)Device_get_rate, NULL, + M_aud_Device_rate_doc, NULL }, + {(char*)"format", (getter)Device_get_format, NULL, + M_aud_Device_format_doc, NULL }, + {(char*)"channels", (getter)Device_get_channels, NULL, + M_aud_Device_channels_doc, NULL }, + {(char*)"volume", (getter)Device_get_volume, (setter)Device_set_volume, + M_aud_Device_volume_doc, NULL }, + {(char*)"listener_location", (getter)Device_get_listener_location, (setter)Device_set_listener_location, + M_aud_Device_listener_location_doc, NULL }, + {(char*)"listener_velocity", (getter)Device_get_listener_velocity, (setter)Device_set_listener_velocity, + M_aud_Device_listener_velocity_doc, NULL }, + {(char*)"listener_orientation", (getter)Device_get_listener_orientation, (setter)Device_set_listener_orientation, + M_aud_Device_listener_orientation_doc, NULL }, + {(char*)"speed_of_sound", (getter)Device_get_speed_of_sound, (setter)Device_set_speed_of_sound, + M_aud_Device_speed_of_sound_doc, NULL }, + {(char*)"doppler_factor", (getter)Device_get_doppler_factor, (setter)Device_set_doppler_factor, + M_aud_Device_doppler_factor_doc, NULL }, + {(char*)"distance_model", (getter)Device_get_distance_model, (setter)Device_set_distance_model, + M_aud_Device_distance_model_doc, NULL }, + {NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(M_aud_Device_doc, + "Device objects represent an audio output backend like OpenAL or " + "SDL, but might also represent a file output or RAM buffer " + "output."); + +static PyTypeObject DeviceType = { + PyVarObject_HEAD_INIT(NULL, 0) + "aud.Device", /* tp_name */ + sizeof(Device), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Device_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_Device_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Device_methods, /* tp_methods */ + 0, /* tp_members */ + Device_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 */ + Device_new, /* tp_new */ +}; + +PyObject * +Device_empty() +{ + return DeviceType.tp_alloc(&DeviceType, 0); +} + +// ==================================================================== + +PyDoc_STRVAR(M_aud_doc, + "This module provides access to the audaspace audio library."); + +static struct PyModuleDef audmodule = { + PyModuleDef_HEAD_INIT, + "aud", /* name of module */ + M_aud_doc, /* module documentation */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + NULL, NULL, NULL, NULL, NULL +}; + +PyMODINIT_FUNC +PyInit_aud(void) +{ + PyObject* m; + + if(PyType_Ready(&FactoryType) < 0) + return NULL; + + if(PyType_Ready(&DeviceType) < 0) + return NULL; + + if(PyType_Ready(&HandleType) < 0) + return NULL; + + m = PyModule_Create(&audmodule); + if(m == NULL) + return NULL; + + Py_INCREF(&FactoryType); + PyModule_AddObject(m, "Factory", (PyObject*)&FactoryType); + + Py_INCREF(&DeviceType); + PyModule_AddObject(m, "Device", (PyObject*)&DeviceType); + + Py_INCREF(&HandleType); + PyModule_AddObject(m, "Handle", (PyObject*)&HandleType); + + AUDError = PyErr_NewException("aud.error", NULL, NULL); + Py_INCREF(AUDError); + PyModule_AddObject(m, "error", AUDError); + + // device constants + PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_NULL); + PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_OPENAL); + PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_SDL); + PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_JACK); + //PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_READ); + // format constants + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_FLOAT32); + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_FLOAT64); + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_INVALID); + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_S16); + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_S24); + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_S32); + PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_U8); + // status constants + PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_INVALID); + PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_PAUSED); + PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_PLAYING); + // distance model constants + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_EXPONENT); + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_EXPONENT_CLAMPED); + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_INVERSE); + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_INVERSE_CLAMPED); + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_LINEAR); + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_LINEAR_CLAMPED); + PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_INVALID); + + return m; +} |