/* * ***** BEGIN GPL LICENSE BLOCK ***** * * Copyright 2009-2011 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 General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Audaspace; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***** END GPL LICENSE BLOCK ***** */ /** \file audaspace/Python/AUD_PyAPI.cpp * \ingroup audpython */ #include "AUD_PyAPI.h" #include #include "AUD_I3DDevice.h" #include "AUD_I3DHandle.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 reinterpret_cast*>(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(kwlist), &filename)) { Py_DECREF(self); return NULL; } try { self->factory = new boost::shared_ptr(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; double rate = 44100; if(!PyArg_ParseTuple(args, "f|d:sine", &frequency, &rate)) return NULL; Factory *self; self = (Factory*)type->tp_alloc(type, 0); if(self != NULL) { try { self->factory = new boost::shared_ptr(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 boost::shared_ptr(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_LowpassFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_DelayFactory(*reinterpret_cast*>(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 = Py_TYPE(self); 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 boost::shared_ptr(new AUD_DoubleFactory(*reinterpret_cast*>(self->factory), *reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_HighpassFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_LimiterFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_PitchFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_VolumeFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_FaderFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_FaderFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_LoopFactory(*reinterpret_cast*>(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 = Py_TYPE(self); 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 boost::shared_ptr(new AUD_SuperposeFactory(*reinterpret_cast*>(self->factory), *reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_PingPongFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_ReverseFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { try { parent->factory = new boost::shared_ptr(new AUD_StreamBufferFactory(*reinterpret_cast*>(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 = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_SquareFactory(*reinterpret_cast*>(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; Py_ssize_t py_a_len; Py_ssize_t py_b_len; 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; } py_a_len= py_a ? PySequence_Size(py_a) : 0; py_b_len= PySequence_Size(py_b); if(!py_b_len || ((py_a != NULL) && !py_b_len)) { PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!"); return NULL; } std::vector 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 NULL; } 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 NULL; } a.push_back(value); } if(a[0] == 0) a[0] = 1; } else a.push_back(1); PyTypeObject* type = Py_TYPE(self); Factory *parent = (Factory*)type->tp_alloc(type, 0); if(parent != NULL) { Py_INCREF(self); parent->child_list = (PyObject *)self; try { parent->factory = new boost::shared_ptr(new AUD_IIRFilterFactory(*reinterpret_cast*>(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) { if(self->handle) delete reinterpret_cast*>(self->handle); 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) { try { return PyBool_FromLong((long)(*reinterpret_cast*>(self->handle))->pause()); } catch(AUD_Exception& e) { PyErr_SetString(AUDError, e.str); return NULL; } } 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) { try { return PyBool_FromLong((long)(*reinterpret_cast*>(self->handle))->resume()); } catch(AUD_Exception& e) { PyErr_SetString(AUDError, e.str); return NULL; } } 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) { try { return PyBool_FromLong((long)(*reinterpret_cast*>(self->handle))->stop()); } catch(AUD_Exception& e) { PyErr_SetString(AUDError, e.str); return NULL; } } 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) { try { return Py_BuildValue("f", (*reinterpret_cast*>(self->handle))->getPosition()); } 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; try { if((*reinterpret_cast*>(self->handle))->seek(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) { try { return PyBool_FromLong((long)(*reinterpret_cast*>(self->handle))->getKeep()); } 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; try { if((*reinterpret_cast*>(self->handle))->setKeep(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) { try { return PyBool_FromLong((long)(*reinterpret_cast*>(self->handle))->getStatus()); } 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) { try { return Py_BuildValue("f", (*reinterpret_cast*>(self->handle))->getVolume()); } 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; try { if((*reinterpret_cast*>(self->handle))->setVolume(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) { try { return Py_BuildValue("f", (*reinterpret_cast*>(self->handle))->getPitch()); } 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; try { if((*reinterpret_cast*>(self->handle))->setPitch(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) { try { return Py_BuildValue("i", (*reinterpret_cast*>(self->handle))->getLoopCount()); } 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; try { if((*reinterpret_cast*>(self->handle))->setLoopCount(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { AUD_Vector3 v = handle->getSourceLocation(); 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { AUD_Vector3 location(x, y, z); if(handle->setSourceLocation(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { AUD_Vector3 v = handle->getSourceVelocity(); 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { AUD_Vector3 velocity(x, y, z); if(handle->setSourceVelocity(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { AUD_Quaternion o = handle->getSourceOrientation(); 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { AUD_Quaternion orientation(w, x, y, z); if(handle->setSourceOrientation(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return PyBool_FromLong((long)handle->isRelative()); } 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); try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setRelative(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getVolumeMinimum()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setVolumeMinimum(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getVolumeMaximum()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setVolumeMaximum(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getDistanceReference()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setDistanceReference(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getDistanceMaximum()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setDistanceMaximum(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getAttenuation()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setAttenuation(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getConeAngleInner()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setConeAngleInner(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getConeAngleOuter()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setConeAngleOuter(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) { try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { return Py_BuildValue("f", handle->getConeVolumeOuter()); } 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; try { AUD_I3DHandle* handle = dynamic_cast(reinterpret_cast*>(self->handle)->get()); if(handle) { if(handle->setConeVolumeOuter(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 reinterpret_cast*>(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; double 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|diiis:Device", const_cast(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: (void)specs; /* quiet warning when others disabled */ self->device = new boost::shared_ptr(new AUD_NULLDevice()); break; case AUD_DEVICE_OPENAL: #ifdef WITH_OPENAL self->device = new boost::shared_ptr(new AUD_OpenALDevice(specs, buffersize)); #endif break; case AUD_DEVICE_SDL: #ifdef WITH_SDL self->device = new boost::shared_ptr(new AUD_SDLDevice(specs, buffersize)); #endif break; case AUD_DEVICE_JACK: #ifdef WITH_JACK self->device = new boost::shared_ptr(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(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) { try { handle->handle = new boost::shared_ptr((*reinterpret_cast*>(self->device))->play(*reinterpret_cast*>(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_stopAll_doc, "stopAll()\n\n" "Stops all playing and paused sounds."); static PyObject * Device_stopAll(Device *self) { try { (*reinterpret_cast*>(self->device))->stopAll(); Py_RETURN_NONE; } catch(AUD_Exception& e) { PyErr_SetString(AUDError, e.str); return NULL; } } 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 { (*reinterpret_cast*>(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 { (*reinterpret_cast*>(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 }, {"stopAll", (PyCFunction)Device_stopAll, METH_NOARGS, M_aud_Device_stopAll_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 = (*reinterpret_cast*>(self->device))->getSpecs(); return Py_BuildValue("d", 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 = (*reinterpret_cast*>(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 = (*reinterpret_cast*>(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", (*reinterpret_cast*>(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 { (*reinterpret_cast*>(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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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(reinterpret_cast*>(self->device)->get()); 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); } PyObject * Factory_empty() { return FactoryType.tp_alloc(&FactoryType, 0); } Factory* checkFactory(PyObject *factory) { if(!PyObject_TypeCheck(factory, &FactoryType)) { PyErr_SetString(PyExc_TypeError, "Object is not of type Factory!"); return NULL; } return (Factory*)factory; } // ==================================================================== 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); PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_STOPPED); // 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; }