Deleting the old internal audaspace. Major changes from there are: - The whole library was refactored to use C++11. - Many stability and performance improvements. - Major Python API refactor: - Most requested: Play self generated sounds using numpy arrays. - For games: Sound list, random sounds and dynamic music. - Writing sounds to files. - Sequencing API. - Opening sound devices, eg. Jack. - Ability to choose different OpenAL devices in the user settings.
1127 lines
26 KiB
C++
1127 lines
26 KiB
C++
/*******************************************************************************
|
|
* Copyright 2009-2016 Jörg Müller
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
******************************************************************************/
|
|
|
|
#include "PyHandle.h"
|
|
|
|
#include "devices/IHandle.h"
|
|
#include "devices/I3DHandle.h"
|
|
#include "Exception.h"
|
|
|
|
#include <memory>
|
|
|
|
#include <structmember.h>
|
|
|
|
using namespace aud;
|
|
|
|
extern PyObject* AUDError;
|
|
static const char* device_not_3d_error = "Device is not a 3D device!";
|
|
|
|
static void
|
|
Handle_dealloc(Handle* self)
|
|
{
|
|
if(self->handle)
|
|
delete reinterpret_cast<std::shared_ptr<IHandle>*>(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<std::shared_ptr<IHandle>*>(self->handle))->pause());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->resume());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->stop());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
},
|
|
{nullptr} /* Sentinel */
|
|
};
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getAttenuation());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
static int
|
|
Handle_set_attenuation(Handle* self, PyObject* args, void* nothing)
|
|
{
|
|
float factor;
|
|
|
|
if(!PyArg_Parse(args, "f:attenuation", &factor))
|
|
return -1;
|
|
|
|
try
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getConeAngleInner());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getConeAngleOuter());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getConeVolumeOuter());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getDistanceMaximum());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getDistanceReference());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->getKeep());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->setKeep(keep))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't set keep of the sound!");
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
Vector3 v = handle->getLocation();
|
|
return Py_BuildValue("(fff)", v.x(), v.y(), v.z());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
Vector3 location(x, y, z);
|
|
if(handle->setLocation(location))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Location couldn't be set!");
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->getLoopCount());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->setLoopCount(loops))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't set the loop count!");
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
Quaternion o = handle->getOrientation();
|
|
return Py_BuildValue("(ffff)", o.w(), o.x(), o.y(), o.z());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
Quaternion orientation(w, x, y, z);
|
|
if(handle->setOrientation(orientation))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't set the orientation!");
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->getPitch());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->setPitch(pitch))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't set the sound pitch!");
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->getPosition());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->seek(position))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't seek the sound!");
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return PyBool_FromLong((long)handle->isRelative());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->getStatus());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
Vector3 v = handle->getVelocity();
|
|
return Py_BuildValue("(fff)", v.x(), v.y(), v.z());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
Vector3 velocity(x, y, z);
|
|
if(handle->setVelocity(velocity))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't set the velocity!");
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->getVolume());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IHandle>*>(self->handle))->setVolume(volume))
|
|
return 0;
|
|
PyErr_SetString(AUDError, "Couldn't set the sound volume!");
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getVolumeMaximum());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(self->handle)->get());
|
|
if(handle)
|
|
{
|
|
return Py_BuildValue("f", handle->getVolumeMinimum());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DHandle* handle = dynamic_cast<I3DHandle*>(reinterpret_cast<std::shared_ptr<IHandle>*>(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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static PyGetSetDef Handle_properties[] = {
|
|
{(char*)"attenuation", (getter)Handle_get_attenuation, (setter)Handle_set_attenuation,
|
|
M_aud_Handle_attenuation_doc, nullptr },
|
|
{(char*)"cone_angle_inner", (getter)Handle_get_cone_angle_inner, (setter)Handle_set_cone_angle_inner,
|
|
M_aud_Handle_cone_angle_inner_doc, nullptr },
|
|
{(char*)"cone_angle_outer", (getter)Handle_get_cone_angle_outer, (setter)Handle_set_cone_angle_outer,
|
|
M_aud_Handle_cone_angle_outer_doc, nullptr },
|
|
{(char*)"cone_volume_outer", (getter)Handle_get_cone_volume_outer, (setter)Handle_set_cone_volume_outer,
|
|
M_aud_Handle_cone_volume_outer_doc, nullptr },
|
|
{(char*)"distance_maximum", (getter)Handle_get_distance_maximum, (setter)Handle_set_distance_maximum,
|
|
M_aud_Handle_distance_maximum_doc, nullptr },
|
|
{(char*)"distance_reference", (getter)Handle_get_distance_reference, (setter)Handle_set_distance_reference,
|
|
M_aud_Handle_distance_reference_doc, nullptr },
|
|
{(char*)"keep", (getter)Handle_get_keep, (setter)Handle_set_keep,
|
|
M_aud_Handle_keep_doc, nullptr },
|
|
{(char*)"location", (getter)Handle_get_location, (setter)Handle_set_location,
|
|
M_aud_Handle_location_doc, nullptr },
|
|
{(char*)"loop_count", (getter)Handle_get_loop_count, (setter)Handle_set_loop_count,
|
|
M_aud_Handle_loop_count_doc, nullptr },
|
|
{(char*)"orientation", (getter)Handle_get_orientation, (setter)Handle_set_orientation,
|
|
M_aud_Handle_orientation_doc, nullptr },
|
|
{(char*)"pitch", (getter)Handle_get_pitch, (setter)Handle_set_pitch,
|
|
M_aud_Handle_pitch_doc, nullptr },
|
|
{(char*)"position", (getter)Handle_get_position, (setter)Handle_set_position,
|
|
M_aud_Handle_position_doc, nullptr },
|
|
{(char*)"relative", (getter)Handle_get_relative, (setter)Handle_set_relative,
|
|
M_aud_Handle_relative_doc, nullptr },
|
|
{(char*)"status", (getter)Handle_get_status, nullptr,
|
|
M_aud_Handle_status_doc, nullptr },
|
|
{(char*)"velocity", (getter)Handle_get_velocity, (setter)Handle_set_velocity,
|
|
M_aud_Handle_velocity_doc, nullptr },
|
|
{(char*)"volume", (getter)Handle_get_volume, (setter)Handle_set_volume,
|
|
M_aud_Handle_volume_doc, nullptr },
|
|
{(char*)"volume_maximum", (getter)Handle_get_volume_maximum, (setter)Handle_set_volume_maximum,
|
|
M_aud_Handle_volume_maximum_doc, nullptr },
|
|
{(char*)"volume_minimum", (getter)Handle_get_volume_minimum, (setter)Handle_set_volume_minimum,
|
|
M_aud_Handle_volume_minimum_doc, nullptr },
|
|
{nullptr} /* 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(nullptr, 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 */
|
|
};
|
|
|
|
|
|
AUD_API PyObject* Handle_empty()
|
|
{
|
|
return HandleType.tp_alloc(&HandleType, 0);
|
|
}
|
|
|
|
|
|
AUD_API Handle*checkHandle(PyObject* handle)
|
|
{
|
|
if(!PyObject_TypeCheck(handle, &HandleType))
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "Object is not of type Handle!");
|
|
return nullptr;
|
|
}
|
|
|
|
return (Handle*)handle;
|
|
}
|
|
|
|
|
|
bool initializeHandle()
|
|
{
|
|
return PyType_Ready(&HandleType) >= 0;
|
|
}
|
|
|
|
|
|
void addHandleToModule(PyObject* module)
|
|
{
|
|
Py_INCREF(&HandleType);
|
|
PyModule_AddObject(module, "Handle", (PyObject *)&HandleType);
|
|
}
|
|
|
|
|