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.
786 lines
19 KiB
C++
786 lines
19 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 "PyDevice.h"
|
|
|
|
#include "PySound.h"
|
|
#include "PyHandle.h"
|
|
|
|
#include "Exception.h"
|
|
#include "devices/IDevice.h"
|
|
#include "devices/I3DDevice.h"
|
|
#include "devices/DeviceManager.h"
|
|
#include "devices/IDeviceFactory.h"
|
|
|
|
#include <structmember.h>
|
|
|
|
using namespace aud;
|
|
|
|
extern PyObject* AUDError;
|
|
static const char* device_not_3d_error = "Device is not a 3D device!";
|
|
|
|
// ====================================================================
|
|
|
|
static void
|
|
Device_dealloc(Device* self)
|
|
{
|
|
if(self->device)
|
|
delete reinterpret_cast<std::shared_ptr<IDevice>*>(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", nullptr};
|
|
const char* device = nullptr;
|
|
double rate = RATE_48000;
|
|
int channels = CHANNELS_STEREO;
|
|
int format = FORMAT_FLOAT32;
|
|
int buffersize = AUD_DEFAULT_BUFFER_SIZE;
|
|
const char* name = "";
|
|
|
|
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|sdiiis:Device", const_cast<char**>(kwlist),
|
|
&device, &rate, &channels, &format, &buffersize, &name))
|
|
return nullptr;
|
|
|
|
if(buffersize < 128)
|
|
{
|
|
PyErr_SetString(PyExc_ValueError, "buffer_size must be at least 128!");
|
|
return nullptr;
|
|
}
|
|
|
|
self = (Device*)type->tp_alloc(type, 0);
|
|
|
|
if(self != nullptr)
|
|
{
|
|
DeviceSpecs specs;
|
|
specs.channels = (Channels)channels;
|
|
specs.format = (SampleFormat)format;
|
|
specs.rate = (SampleRate)rate;
|
|
|
|
self->device = nullptr;
|
|
|
|
try
|
|
{
|
|
if(!device)
|
|
{
|
|
auto dev = DeviceManager::getDevice();
|
|
if(!dev)
|
|
{
|
|
DeviceManager::openDefaultDevice();
|
|
dev = DeviceManager::getDevice();
|
|
}
|
|
self->device = new std::shared_ptr<IDevice>(dev);
|
|
}
|
|
else
|
|
{
|
|
std::shared_ptr<IDeviceFactory> factory;
|
|
if(!*device)
|
|
factory = DeviceManager::getDefaultDeviceFactory();
|
|
else
|
|
factory = DeviceManager::getDeviceFactory(device);
|
|
|
|
if(factory)
|
|
{
|
|
factory->setName(name);
|
|
factory->setSpecs(specs);
|
|
factory->setBufferSize(buffersize);
|
|
self->device = new std::shared_ptr<IDevice>(factory->openDevice());
|
|
}
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
Py_DECREF(self);
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
|
|
if(!self->device)
|
|
{
|
|
Py_DECREF(self);
|
|
PyErr_SetString(AUDError, "Unsupported device type!");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return (PyObject *)self;
|
|
}
|
|
|
|
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<std::shared_ptr<IDevice>*>(self->device))->lock();
|
|
Py_RETURN_NONE;
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyDoc_STRVAR(M_aud_Device_play_doc,
|
|
"play(sound, keep=False)\n\n"
|
|
"Plays a sound.\n\n"
|
|
":arg sound: The sound to play.\n"
|
|
":type sound: :class:`Sound`\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 = nullptr;
|
|
|
|
bool keep = false;
|
|
|
|
static const char* kwlist[] = {"sound", "keep", nullptr};
|
|
|
|
if(!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:play", const_cast<char**>(kwlist), &object, &keepo))
|
|
return nullptr;
|
|
|
|
Sound* sound = checkSound(object);
|
|
|
|
if(!sound)
|
|
return nullptr;
|
|
|
|
if(keepo != nullptr)
|
|
{
|
|
if(!PyBool_Check(keepo))
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "keep is not a boolean!");
|
|
return nullptr;
|
|
}
|
|
|
|
keep = keepo == Py_True;
|
|
}
|
|
|
|
Handle* handle;
|
|
|
|
handle = (Handle*)Handle_empty();
|
|
if(handle != nullptr)
|
|
{
|
|
try
|
|
{
|
|
handle->handle = new std::shared_ptr<IHandle>((*reinterpret_cast<std::shared_ptr<IDevice>*>(self->device))->play(*reinterpret_cast<std::shared_ptr<ISound>*>(sound->sound), keep));
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
Py_DECREF(handle);
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IDevice>*>(self->device))->stopAll();
|
|
Py_RETURN_NONE;
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IDevice>*>(self->device))->unlock();
|
|
Py_RETURN_NONE;
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
static PyMethodDef Device_methods[] = {
|
|
{"lock", (PyCFunction)Device_lock, METH_NOARGS,
|
|
M_aud_Device_lock_doc
|
|
},
|
|
{"play", (PyCFunction)Device_play, METH_VARARGS | METH_KEYWORDS,
|
|
M_aud_Device_play_doc
|
|
},
|
|
{"stopAll", (PyCFunction)Device_stopAll, METH_NOARGS,
|
|
M_aud_Device_stopAll_doc
|
|
},
|
|
{"unlock", (PyCFunction)Device_unlock, METH_NOARGS,
|
|
M_aud_Device_unlock_doc
|
|
},
|
|
{nullptr} /* Sentinel */
|
|
};
|
|
|
|
PyDoc_STRVAR(M_aud_Device_channels_doc,
|
|
"The channel count of the device.");
|
|
|
|
static PyObject *
|
|
Device_get_channels(Device* self, void* nothing)
|
|
{
|
|
try
|
|
{
|
|
DeviceSpecs specs = (*reinterpret_cast<std::shared_ptr<IDevice>*>(self->device))->getSpecs();
|
|
return Py_BuildValue("i", specs.channels);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
return Py_BuildValue("i", int(device->getDistanceModel()));
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
device->setDistanceModel(DistanceModel(model));
|
|
return 0;
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
return Py_BuildValue("f", device->getDopplerFactor());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
device->setDopplerFactor(factor);
|
|
return 0;
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
PyDoc_STRVAR(M_aud_Device_format_doc,
|
|
"The native sample format of the device.");
|
|
|
|
static PyObject *
|
|
Device_get_format(Device* self, void* nothing)
|
|
{
|
|
try
|
|
{
|
|
DeviceSpecs specs = (*reinterpret_cast<std::shared_ptr<IDevice>*>(self->device))->getSpecs();
|
|
return Py_BuildValue("i", specs.format);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
Vector3 v = device->getListenerLocation();
|
|
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
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
Vector3 location(x, y, z);
|
|
device->setListenerLocation(location);
|
|
return 0;
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
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(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
Quaternion orientation(w, x, y, z);
|
|
device->setListenerOrientation(orientation);
|
|
return 0;
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
Vector3 v = device->getListenerVelocity();
|
|
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
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
Vector3 velocity(x, y, z);
|
|
device->setListenerVelocity(velocity);
|
|
return 0;
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
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
|
|
{
|
|
DeviceSpecs specs = (*reinterpret_cast<std::shared_ptr<IDevice>*>(self->device))->getSpecs();
|
|
return Py_BuildValue("d", specs.rate);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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.3 m/s.");
|
|
|
|
static PyObject *
|
|
Device_get_speed_of_sound(Device* self, void* nothing)
|
|
{
|
|
try
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
return Py_BuildValue("f", device->getSpeedOfSound());
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
return nullptr;
|
|
}
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
I3DDevice* device = dynamic_cast<I3DDevice*>(reinterpret_cast<std::shared_ptr<IDevice>*>(self->device)->get());
|
|
if(device)
|
|
{
|
|
device->setSpeedOfSound(speed);
|
|
return 0;
|
|
}
|
|
else
|
|
PyErr_SetString(AUDError, device_not_3d_error);
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
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<std::shared_ptr<IDevice>*>(self->device))->getVolume());
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
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<std::shared_ptr<IDevice>*>(self->device))->setVolume(volume);
|
|
return 0;
|
|
}
|
|
catch(Exception& e)
|
|
{
|
|
PyErr_SetString(AUDError, e.what());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static PyGetSetDef Device_properties[] = {
|
|
{(char*)"channels", (getter)Device_get_channels, nullptr,
|
|
M_aud_Device_channels_doc, nullptr },
|
|
{(char*)"distance_model", (getter)Device_get_distance_model, (setter)Device_set_distance_model,
|
|
M_aud_Device_distance_model_doc, nullptr },
|
|
{(char*)"doppler_factor", (getter)Device_get_doppler_factor, (setter)Device_set_doppler_factor,
|
|
M_aud_Device_doppler_factor_doc, nullptr },
|
|
{(char*)"format", (getter)Device_get_format, nullptr,
|
|
M_aud_Device_format_doc, nullptr },
|
|
{(char*)"listener_location", (getter)Device_get_listener_location, (setter)Device_set_listener_location,
|
|
M_aud_Device_listener_location_doc, nullptr },
|
|
{(char*)"listener_orientation", (getter)Device_get_listener_orientation, (setter)Device_set_listener_orientation,
|
|
M_aud_Device_listener_orientation_doc, nullptr },
|
|
{(char*)"listener_velocity", (getter)Device_get_listener_velocity, (setter)Device_set_listener_velocity,
|
|
M_aud_Device_listener_velocity_doc, nullptr },
|
|
{(char*)"rate", (getter)Device_get_rate, nullptr,
|
|
M_aud_Device_rate_doc, nullptr },
|
|
{(char*)"speed_of_sound", (getter)Device_get_speed_of_sound, (setter)Device_set_speed_of_sound,
|
|
M_aud_Device_speed_of_sound_doc, nullptr },
|
|
{(char*)"volume", (getter)Device_get_volume, (setter)Device_set_volume,
|
|
M_aud_Device_volume_doc, nullptr },
|
|
{nullptr} /* 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(nullptr, 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 */
|
|
};
|
|
|
|
AUD_API PyObject* Device_empty()
|
|
{
|
|
return DeviceType.tp_alloc(&DeviceType, 0);
|
|
}
|
|
|
|
|
|
AUD_API Device* checkDevice(PyObject* device)
|
|
{
|
|
if(!PyObject_TypeCheck(device, &DeviceType))
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "Object is not of type Device!");
|
|
return nullptr;
|
|
}
|
|
|
|
return (Device*)device;
|
|
}
|
|
|
|
|
|
bool initializeDevice()
|
|
{
|
|
return PyType_Ready(&DeviceType) >= 0;
|
|
}
|
|
|
|
|
|
void addDeviceToModule(PyObject* module)
|
|
{
|
|
Py_INCREF(&DeviceType);
|
|
PyModule_AddObject(module, "Device", (PyObject *)&DeviceType);
|
|
}
|