/******************************************************************************* * 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 "PySequence.h" #include "PySound.h" #include "PySequenceEntry.h" #include "sequence/AnimateableProperty.h" #include "sequence/Sequence.h" #include "Exception.h" #include #include using aud::Channels; using aud::DistanceModel; using aud::Exception; using aud::ISound; using aud::AnimateableProperty; using aud::AnimateablePropertyType; using aud::Specs; extern PyObject* AUDError; // ==================================================================== static void Sequence_dealloc(Sequence* self) { if(self->sequence) delete reinterpret_cast*>(self->sequence); Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject * Sequence_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { Sequence* self; int channels = aud::CHANNELS_STEREO; double rate = aud::RATE_48000; float fps = 30.0f; bool muted = false; PyObject* mutedo = nullptr; self = (Sequence*)type->tp_alloc(type, 0); if(self != nullptr) { static const char* kwlist[] = {"channels", "rate", "fps", "muted", nullptr}; if(!PyArg_ParseTupleAndKeywords(args, kwds, "|idfO:Sequence", const_cast(kwlist), &channels, &rate, &fps, &mutedo)) { Py_DECREF(self); return nullptr; } if(mutedo) { if(!PyBool_Check(mutedo)) { PyErr_SetString(PyExc_TypeError, "muted is not a boolean!"); return nullptr; } muted = mutedo == Py_True; } aud::Specs specs; specs.channels = static_cast(channels); specs.rate = rate; try { self->sequence = new std::shared_ptr(new aud::Sequence(specs, fps, muted)); } catch(Exception& e) { Py_DECREF(self); PyErr_SetString(AUDError, e.what()); return nullptr; } } return (PyObject *)self; } PyDoc_STRVAR(M_aud_Sequence_add_doc, "add()\n\n" "Adds a new entry to the sequence.\n\n" ":arg sound: The sound this entry should play.\n" ":type sound: :class:`Sound`\n" ":arg begin: The start time.\n" ":type begin: float\n" ":arg end: The end time or a negative value if determined by the sound.\n" ":type end: float\n" ":arg skip: How much seconds should be skipped at the beginning.\n" ":type skip: float\n" ":return: The entry added.\n" ":rtype: :class:`SequenceEntry`"); static PyObject * Sequence_add(Sequence* self, PyObject* args, PyObject* kwds) { PyObject* object; float begin; float end = -1.0f; float skip = 0.0f; static const char* kwlist[] = {"sound", "begin", "end", "skip", nullptr}; if(!PyArg_ParseTupleAndKeywords(args, kwds, "Of|ff:add", const_cast(kwlist), &object, &begin, &end, &skip)) return nullptr; Sound* sound = checkSound(object); if(!sound) return nullptr; SequenceEntry* entry; entry = (SequenceEntry*)SequenceEntry_empty(); if(entry != nullptr) { try { entry->entry = new std::shared_ptr((*reinterpret_cast*>(self->sequence))->add(*reinterpret_cast*>(sound->sound), begin, end, skip)); } catch(Exception& e) { Py_DECREF(entry); PyErr_SetString(AUDError, e.what()); return nullptr; } } return (PyObject *)entry; } PyDoc_STRVAR(M_aud_Sequence_remove_doc, "remove()\n\n" "Removes an entry from the sequence.\n\n" ":arg entry: The entry to remove.\n" ":type entry: :class:`SequenceEntry`\n"); static PyObject * Sequence_remove(Sequence* self, PyObject* args) { PyObject* object; if(!PyArg_ParseTuple(args, "O:remove", &object)) return nullptr; SequenceEntry* entry = checkSequenceEntry(object); if(!entry) return nullptr; try { (*reinterpret_cast*>(self->sequence))->remove(*reinterpret_cast*>(entry->entry)); Py_RETURN_NONE; } catch(Exception& e) { Py_DECREF(entry); PyErr_SetString(AUDError, e.what()); return nullptr; } } PyDoc_STRVAR(M_aud_Sequence_setAnimationData_doc, "setAnimationData()\n\n" "Writes animation data to a sequence.\n\n" ":arg type: The type of animation data.\n" ":type type: int\n" ":arg frame: The frame this data is for.\n" ":type frame: int\n" ":arg data: The data to write.\n" ":type data: sequence of float\n" ":arg animated: Whether the attribute is animated.\n" ":type animated: bool"); static PyObject * Sequence_setAnimationData(Sequence* self, PyObject* args) { int type, frame; PyObject* py_data; Py_ssize_t py_data_len; PyObject* animatedo; bool animated; if(!PyArg_ParseTuple(args, "iiOO:setAnimationData", &type, &frame, &py_data, &animatedo)) return nullptr; if(!PySequence_Check(py_data)) { PyErr_SetString(PyExc_TypeError, "Parameter is not a sequence!"); return nullptr; } py_data_len= PySequence_Size(py_data); std::vector data; data.resize(py_data_len); PyObject* py_value; float value; for(Py_ssize_t i = 0; i < py_data_len; i++) { py_value = PySequence_GetItem(py_data, i); value= (float)PyFloat_AsDouble(py_value); Py_DECREF(py_value); if(value == -1.0f && PyErr_Occurred()) { return nullptr; } data.push_back(value); } if(!PyBool_Check(animatedo)) { PyErr_SetString(PyExc_TypeError, "animated is not a boolean!"); return nullptr; } animated = animatedo == Py_True; try { AnimateableProperty* prop = (*reinterpret_cast*>(self->sequence))->getAnimProperty(static_cast(type)); if(prop->getCount() != py_data_len) { PyErr_SetString(PyExc_ValueError, "the amount of floats doesn't fit the animated property"); return nullptr; } if(animated) { if(frame >= 0) prop->write(&data[0], frame, 1); } else { prop->write(&data[0]); } Py_RETURN_NONE; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static PyMethodDef Sequence_methods[] = { {"add", (PyCFunction)Sequence_add, METH_VARARGS | METH_KEYWORDS, M_aud_Sequence_add_doc }, {"remove", (PyCFunction)Sequence_remove, METH_VARARGS, M_aud_Sequence_remove_doc }, {"setAnimationData", (PyCFunction)Sequence_setAnimationData, METH_VARARGS, M_aud_Sequence_setAnimationData_doc }, {nullptr} /* Sentinel */ }; PyDoc_STRVAR(M_aud_Sequence_channels_doc, "The channel count of the sequence."); static PyObject * Sequence_get_channels(Sequence* self, void* nothing) { try { Specs specs = (*reinterpret_cast*>(self->sequence))->getSpecs(); return Py_BuildValue("i", specs.channels); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_channels(Sequence* self, PyObject* args, void* nothing) { int channels; if(!PyArg_Parse(args, "i:channels", &channels)) return -1; try { std::shared_ptr sequence = *reinterpret_cast*>(self->sequence); Specs specs = sequence->getSpecs(); specs.channels = static_cast(channels); sequence->setSpecs(specs); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return -1; } } PyDoc_STRVAR(M_aud_Sequence_distance_model_doc, "The distance model of the sequence.\n\n" ".. seealso:: http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm#_Toc199835864"); static PyObject * Sequence_get_distance_model(Sequence* self, void* nothing) { try { return Py_BuildValue("i", (*reinterpret_cast*>(self->sequence))->getDistanceModel()); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_distance_model(Sequence* self, PyObject* args, void* nothing) { int distance_model; if(!PyArg_Parse(args, "i:distance_model", &distance_model)) return -1; try { (*reinterpret_cast*>(self->sequence))->setDistanceModel(static_cast(distance_model)); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return -1; } } PyDoc_STRVAR(M_aud_Sequence_doppler_factor_doc, "The doppler factor of the sequence.\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 * Sequence_get_doppler_factor(Sequence* self, void* nothing) { try { return Py_BuildValue("f", (*reinterpret_cast*>(self->sequence))->getDopplerFactor()); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_doppler_factor(Sequence* self, PyObject* args, void* nothing) { float factor; if(!PyArg_Parse(args, "f:doppler_factor", &factor)) return -1; try { (*reinterpret_cast*>(self->sequence))->setDopplerFactor(factor); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return -1; } } PyDoc_STRVAR(M_aud_Sequence_fps_doc, "The listeners's location in 3D space, a 3D tuple of floats."); static PyObject * Sequence_get_fps(Sequence* self, void* nothing) { try { return Py_BuildValue("f", (*reinterpret_cast*>(self->sequence))->getFPS()); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_fps(Sequence* self, PyObject* args, void* nothing) { float fps; if(!PyArg_Parse(args, "f:fps", &fps)) return -1; try { (*reinterpret_cast*>(self->sequence))->setFPS(fps); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return -1; } } PyDoc_STRVAR(M_aud_Sequence_muted_doc, "Whether the whole sequence is muted.\n"); static PyObject * Sequence_get_muted(Sequence* self, void* nothing) { try { std::shared_ptr* sequence = reinterpret_cast*>(self->sequence); return PyBool_FromLong((long)(*sequence)->isMuted()); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_muted(Sequence* self, PyObject* args, void* nothing) { if(!PyBool_Check(args)) { PyErr_SetString(PyExc_TypeError, "muted is not a boolean!"); return -1; } bool muted = args == Py_True; try { std::shared_ptr* sequence = reinterpret_cast*>(self->sequence); (*sequence)->mute(muted); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); } return -1; } PyDoc_STRVAR(M_aud_Sequence_rate_doc, "The sampling rate of the sequence in Hz."); static PyObject * Sequence_get_rate(Sequence* self, void* nothing) { try { Specs specs = (*reinterpret_cast*>(self->sequence))->getSpecs(); return Py_BuildValue("d", specs.rate); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_rate(Sequence* self, PyObject* args, void* nothing) { double rate; if(!PyArg_Parse(args, "d:rate", &rate)) return -1; try { std::shared_ptr sequence = *reinterpret_cast*>(self->sequence); Specs specs = sequence->getSpecs(); specs.rate = rate; sequence->setSpecs(specs); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return -1; } } PyDoc_STRVAR(M_aud_Sequence_speed_of_sound_doc, "The speed of sound of the sequence.\n" "The speed of sound in air is typically 343.3 m/s."); static PyObject * Sequence_get_speed_of_sound(Sequence* self, void* nothing) { try { return Py_BuildValue("f", (*reinterpret_cast*>(self->sequence))->getSpeedOfSound()); } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return nullptr; } } static int Sequence_set_speed_of_sound(Sequence* self, PyObject* args, void* nothing) { float speed; if(!PyArg_Parse(args, "f:speed_of_sound", &speed)) return -1; try { (*reinterpret_cast*>(self->sequence))->setSpeedOfSound(speed); return 0; } catch(Exception& e) { PyErr_SetString(AUDError, e.what()); return -1; } } static PyGetSetDef Sequence_properties[] = { {(char*)"channels", (getter)Sequence_get_channels, (setter)Sequence_set_channels, M_aud_Sequence_channels_doc, nullptr }, {(char*)"distance_model", (getter)Sequence_get_distance_model, (setter)Sequence_set_distance_model, M_aud_Sequence_distance_model_doc, nullptr }, {(char*)"doppler_factor", (getter)Sequence_get_doppler_factor, (setter)Sequence_set_doppler_factor, M_aud_Sequence_doppler_factor_doc, nullptr }, {(char*)"fps", (getter)Sequence_get_fps, (setter)Sequence_set_fps, M_aud_Sequence_fps_doc, nullptr }, {(char*)"muted", (getter)Sequence_get_muted, (setter)Sequence_set_muted, M_aud_Sequence_muted_doc, nullptr }, {(char*)"rate", (getter)Sequence_get_rate, (setter)Sequence_set_rate, M_aud_Sequence_rate_doc, nullptr }, {(char*)"speed_of_sound", (getter)Sequence_get_speed_of_sound, (setter)Sequence_set_speed_of_sound, M_aud_Sequence_speed_of_sound_doc, nullptr }, {nullptr} /* Sentinel */ }; PyDoc_STRVAR(M_aud_Sequence_doc, "This sound represents sequenced entries to play a sound sequence."); extern PyTypeObject SoundType; static PyTypeObject SequenceType = { PyVarObject_HEAD_INIT(nullptr, 0) "aud.Sequence", /* tp_name */ sizeof(Sequence), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)Sequence_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_Sequence_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Sequence_methods, /* tp_methods */ 0, /* tp_members */ Sequence_properties, /* tp_getset */ &SoundType, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ Sequence_new, /* tp_new */ }; AUD_API PyObject* Sequence_empty() { return SequenceType.tp_alloc(&SequenceType, 0); } AUD_API Sequence* checkSequence(PyObject* sequence) { if(!PyObject_TypeCheck(sequence, &SequenceType)) { PyErr_SetString(PyExc_TypeError, "Object is not of type Sequence!"); return nullptr; } return (Sequence*)sequence; } bool initializeSequence() { return PyType_Ready(&SequenceType) >= 0; } void addSequenceToModule(PyObject* module) { Py_INCREF(&SequenceType); PyModule_AddObject(module, "Sequence", (PyObject *)&SequenceType); }