1 /*******************************************************************************
2 * Copyright 2015-2016 Juan Francisco Crespo Galán
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *   http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 ******************************************************************************/
16 
17 #include "PyDynamicMusic.h"
18 #include "PySound.h"
19 #include "PyHandle.h"
20 #include "PyDevice.h"
21 
22 #include "Exception.h"
23 #include "fx/DynamicMusic.h"
24 
25 extern PyObject* AUDError;
26 
27 static PyObject *
DynamicMusic_new(PyTypeObject * type,PyObject * args,PyObject * kwds)28 DynamicMusic_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
29 {
30 	DynamicMusicP* self = (DynamicMusicP*)type->tp_alloc(type, 0);
31 
32 	if(self != nullptr)
33 	{
34 		PyObject* object;
35 		if(!PyArg_ParseTuple(args, "O:device", &object))
36 			return nullptr;
37 		Device* device = checkDevice(object);
38 
39 		try
40 		{
41 			self->dynamicMusic = new std::shared_ptr<aud::DynamicMusic>(new aud::DynamicMusic(*reinterpret_cast<std::shared_ptr<aud::IDevice>*>(device->device)));
42 		}
43 		catch(aud::Exception& e)
44 		{
45 			Py_DECREF(self);
46 			PyErr_SetString(AUDError, e.what());
47 			return nullptr;
48 		}
49 	}
50 
51 	return (PyObject *)self;
52 }
53 
54 static void
DynamicMusic_dealloc(DynamicMusicP * self)55 DynamicMusic_dealloc(DynamicMusicP* self)
56 {
57 	if(self->dynamicMusic)
58 		delete reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic);
59 	Py_TYPE(self)->tp_free((PyObject *)self);
60 }
61 
62 PyDoc_STRVAR(M_aud_DynamicMusic_addScene_doc,
63 	".. classmethod:: addScene(scene)\n\n"
64 	"   Adds a new scene.\n\n"
65 	"   :arg scene: The scene sound.\n"
66 	"   :type scene: :class:`Sound`\n"
67 	"   :return: The new scene id.\n"
68 	"   :rtype: int");
69 
70 static PyObject *
DynamicMusic_addScene(DynamicMusicP * self,PyObject * args)71 DynamicMusic_addScene(DynamicMusicP* self, PyObject* args)
72 {
73 	PyObject* object;
74 	if(!PyArg_Parse(args, "O:sound", &object))
75 		return nullptr;
76 
77 	Sound* sound = checkSound(object);
78 	if(!sound)
79 		return nullptr;
80 
81 	try
82 	{
83 		return Py_BuildValue("i", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->addScene(*reinterpret_cast<std::shared_ptr<aud::ISound>*>(sound->sound)));
84 	}
85 	catch(aud::Exception& e)
86 	{
87 		PyErr_SetString(AUDError, e.what());
88 		return nullptr;
89 	}
90 }
91 
92 PyDoc_STRVAR(M_aud_DynamicMusic_addTransition_doc,
93 	".. classmethod:: addTransition(ini, end, transition)\n\n"
94 	"   Adds a new scene.\n\n"
95 	"   :arg ini: the initial scene foor the transition.\n"
96 	"   :type ini: int\n"
97 	"   :arg end: The final scene for the transition.\n"
98 	"   :type end: int\n"
99 	"   :arg transition: The transition sound.\n"
100 	"   :type transition: :class:`Sound`\n"
101 	"   :return: false if the ini or end scenes don't exist, true othrwise.\n"
102 	"   :rtype: bool");
103 
104 static PyObject *
DynamicMusic_addTransition(DynamicMusicP * self,PyObject * args)105 DynamicMusic_addTransition(DynamicMusicP* self, PyObject* args)
106 {
107 	PyObject* object;
108 	int ini, end;
109 	if(!PyArg_ParseTuple(args, "iiO:sound", &ini, &end, &object))
110 		return nullptr;
111 	Sound* sound = checkSound(object);
112 	if(!sound)
113 		return nullptr;
114 
115 	try
116 	{
117 		(*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->addTransition(ini, end, *reinterpret_cast<std::shared_ptr<aud::ISound>*>(sound->sound));
118 		Py_RETURN_NONE;
119 	}
120 	catch(aud::Exception& e)
121 	{
122 		PyErr_SetString(AUDError, e.what());
123 		return nullptr;
124 	}
125 }
126 
127 PyDoc_STRVAR(M_aud_DynamicMusic_resume_doc,
128 	".. classmethod:: resume()\n\n"
129 	"   Resumes playback of the scene.\n\n"
130 	"   :return: Whether the action succeeded.\n"
131 	"   :rtype: bool");
132 
133 static PyObject *
DynamicMusic_resume(DynamicMusicP * self)134 DynamicMusic_resume(DynamicMusicP* self)
135 {
136 	try
137 	{
138 		return PyBool_FromLong((long)(*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->resume());
139 	}
140 	catch(aud::Exception& e)
141 	{
142 		PyErr_SetString(AUDError, e.what());
143 		return nullptr;
144 	}
145 }
146 
147 PyDoc_STRVAR(M_aud_DynamicMusic_pause_doc,
148 	".. classmethod:: pause()\n\n"
149 	"   Pauses playback of the scene.\n\n"
150 	"   :return: Whether the action succeeded.\n"
151 	"   :rtype: bool");
152 
153 static PyObject *
DynamicMusic_pause(DynamicMusicP * self)154 DynamicMusic_pause(DynamicMusicP* self)
155 {
156 	try
157 	{
158 		return PyBool_FromLong((long)(*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->pause());
159 	}
160 	catch(aud::Exception& e)
161 	{
162 		PyErr_SetString(AUDError, e.what());
163 		return nullptr;
164 	}
165 }
166 
167 PyDoc_STRVAR(M_aud_DynamicMusic_stop_doc,
168 	".. classmethod:: stop()\n\n"
169 	"   Stops playback of the scene.\n\n"
170 	"   :return: Whether the action succeeded.\n"
171 	"   :rtype: bool\n\n");
172 
173 static PyObject *
DynamicMusic_stop(DynamicMusicP * self)174 DynamicMusic_stop(DynamicMusicP* self)
175 {
176 	try
177 	{
178 		return PyBool_FromLong((long)(*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->stop());
179 	}
180 	catch(aud::Exception& e)
181 	{
182 		PyErr_SetString(AUDError, e.what());
183 		return nullptr;
184 	}
185 }
186 
187 static PyMethodDef DynamicMusic_methods[] = {
188 	{ "addScene", (PyCFunction)DynamicMusic_addScene, METH_O,
189 	M_aud_DynamicMusic_addScene_doc
190 	},
191 	{ "addTransition", (PyCFunction)DynamicMusic_addTransition, METH_VARARGS,
192 	M_aud_DynamicMusic_addTransition_doc
193 	},
194 	{ "resume", (PyCFunction)DynamicMusic_resume, METH_NOARGS,
195 	M_aud_DynamicMusic_resume_doc
196 	},
197 	{ "pause", (PyCFunction)DynamicMusic_pause, METH_NOARGS,
198 	M_aud_DynamicMusic_pause_doc
199 	},
200 	{ "stop", (PyCFunction)DynamicMusic_stop, METH_NOARGS,
201 	M_aud_DynamicMusic_stop_doc
202 	},
203 	{ nullptr }  /* Sentinel */
204 };
205 
206 /////////////////////////////////////////////////////
207 
208 PyDoc_STRVAR(M_aud_DynamicMusic_status_doc,
209 	"Whether the scene is playing, paused or stopped (=invalid).");
210 
211 static PyObject *
DynamicMusic_get_status(DynamicMusicP * self,void * nothing)212 DynamicMusic_get_status(DynamicMusicP* self, void* nothing)
213 {
214 	try
215 	{
216 		return PyBool_FromLong((long)(*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getStatus());
217 	}
218 	catch(aud::Exception& e)
219 	{
220 		PyErr_SetString(AUDError, e.what());
221 		return nullptr;
222 	}
223 }
224 
225 PyDoc_STRVAR(M_aud_DynamicMusic_position_doc,
226 	"The playback position of the scene in seconds.");
227 
228 static int
DynamicMusic_set_position(DynamicMusicP * self,PyObject * args,void * nothing)229 DynamicMusic_set_position(DynamicMusicP* self, PyObject* args, void* nothing)
230 {
231 	double position;
232 
233 	if(!PyArg_Parse(args, "d:position", &position))
234 		return -1;
235 
236 	try
237 	{
238 		if((*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->seek(position))
239 			return 0;
240 		PyErr_SetString(AUDError, "Couldn't seek the sound!");
241 	}
242 	catch(aud::Exception& e)
243 	{
244 		PyErr_SetString(AUDError, e.what());
245 	}
246 
247 	return -1;
248 }
249 
250 static PyObject *
DynamicMusic_get_position(DynamicMusicP * self,void * nothing)251 DynamicMusic_get_position(DynamicMusicP* self, void* nothing)
252 {
253 	try
254 	{
255 		return Py_BuildValue("d", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getPosition());
256 	}
257 	catch(aud::Exception& e)
258 	{
259 		PyErr_SetString(AUDError, e.what());
260 		return nullptr;
261 	}
262 }
263 
264 PyDoc_STRVAR(M_aud_DynamicMusic_fadeTime_doc,
265 	"The length in seconds of the crossfade transition");
266 
267 static int
DynamicMusic_set_fadeTime(DynamicMusicP * self,PyObject * args,void * nothing)268 DynamicMusic_set_fadeTime(DynamicMusicP* self, PyObject* args, void* nothing)
269 {
270 	float fadeTime;
271 
272 	if(!PyArg_Parse(args, "f:fadeTime", &fadeTime))
273 		return -1;
274 
275 	try
276 	{
277 		(*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->setFadeTime(fadeTime);
278 		return 0;
279 	}
280 	catch(aud::Exception& e)
281 	{
282 		PyErr_SetString(AUDError, e.what());
283 	}
284 
285 	return -1;
286 }
287 
288 static PyObject *
DynamicMusic_get_fadeTime(DynamicMusicP * self,void * nothing)289 DynamicMusic_get_fadeTime(DynamicMusicP* self, void* nothing)
290 {
291 	try
292 	{
293 		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getFadeTime());
294 	}
295 	catch(aud::Exception& e)
296 	{
297 		PyErr_SetString(AUDError, e.what());
298 		return nullptr;
299 	}
300 }
301 
302 PyDoc_STRVAR(M_aud_DynamicMusic_scene_doc,
303 	"The current scene");
304 
305 static int
DynamicMusic_set_scene(DynamicMusicP * self,PyObject * args,void * nothing)306 DynamicMusic_set_scene(DynamicMusicP* self, PyObject* args, void* nothing)
307 {
308 	int scene;
309 
310 	if(!PyArg_Parse(args, "i:scene", &scene))
311 		return -1;
312 
313 	try
314 	{
315 		if((*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->changeScene(scene))
316 			return 0;
317 		PyErr_SetString(AUDError, "Couldn't change the scene!");
318 	}
319 	catch(aud::Exception& e)
320 	{
321 		PyErr_SetString(AUDError, e.what());
322 	}
323 
324 	return -1;
325 }
326 
327 static PyObject *
DynamicMusic_get_scene(DynamicMusicP * self,void * nothing)328 DynamicMusic_get_scene(DynamicMusicP* self, void* nothing)
329 {
330 	try
331 	{
332 		return Py_BuildValue("i", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getScene());
333 	}
334 	catch(aud::Exception& e)
335 	{
336 		PyErr_SetString(AUDError, e.what());
337 		return nullptr;
338 	}
339 }
340 
341 PyDoc_STRVAR(M_aud_DynamicMusic_volume_doc,
342 	"The volume of the scene.");
343 
344 static int
DynamicMusic_set_volume(DynamicMusicP * self,PyObject * args,void * nothing)345 DynamicMusic_set_volume(DynamicMusicP* self, PyObject* args, void* nothing)
346 {
347 	float volume;
348 
349 	if(!PyArg_Parse(args, "f:volume", &volume))
350 		return -1;
351 
352 	try
353 	{
354 		if((*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->setVolume(volume))
355 			return 0;
356 		PyErr_SetString(AUDError, "Couldn't change the volume!");
357 	}
358 	catch(aud::Exception& e)
359 	{
360 		PyErr_SetString(AUDError, e.what());
361 	}
362 
363 	return -1;
364 }
365 
366 static PyObject *
DynamicMusic_get_volume(DynamicMusicP * self,void * nothing)367 DynamicMusic_get_volume(DynamicMusicP* self, void* nothing)
368 {
369 	try
370 	{
371 		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::DynamicMusic>*>(self->dynamicMusic))->getVolume());
372 	}
373 	catch(aud::Exception& e)
374 	{
375 		PyErr_SetString(AUDError, e.what());
376 		return nullptr;
377 	}
378 }
379 
380 static PyGetSetDef DynamicMusic_properties[] = {
381 	{ (char*)"status", (getter)DynamicMusic_get_status, nullptr,
382 	M_aud_DynamicMusic_status_doc, nullptr },
383 	{ (char*)"position", (getter)DynamicMusic_get_position, (setter)DynamicMusic_set_position,
384 	M_aud_DynamicMusic_position_doc, nullptr },
385 	{ (char*)"fadeTime", (getter)DynamicMusic_get_fadeTime, (setter)DynamicMusic_set_fadeTime,
386 	M_aud_DynamicMusic_fadeTime_doc, nullptr },
387 	{ (char*)"scene", (getter)DynamicMusic_get_scene, (setter)DynamicMusic_set_scene,
388 	M_aud_DynamicMusic_scene_doc, nullptr },
389 	{ (char*)"volume", (getter)DynamicMusic_get_volume, (setter)DynamicMusic_set_volume,
390 	M_aud_DynamicMusic_volume_doc, nullptr },
391 	{ nullptr }  /* Sentinel */
392 };
393 
394 PyDoc_STRVAR(M_aud_DynamicMusic_doc,
395 	"The DynamicMusic object allows to play music depending on a current scene, scene changes are managed by the class, with the possibility of custom transitions.\n"
396 	"The default transition is a crossfade effect, and the default scene is silent and has id 0");
397 
398 PyTypeObject DynamicMusicType = {
399 	PyVarObject_HEAD_INIT(nullptr, 0)
400 	"aud.DynamicMusic",						/* tp_name */
401 	sizeof(DynamicMusicP),					/* tp_basicsize */
402 	0,										/* tp_itemsize */
403 	(destructor)DynamicMusic_dealloc,		/* tp_dealloc */
404 	0,										/* tp_print */
405 	0,										/* tp_getattr */
406 	0,										/* tp_setattr */
407 	0,										/* tp_reserved */
408 	0,										/* tp_repr */
409 	0,										/* tp_as_number */
410 	0,										/* tp_as_sequence */
411 	0,										/* tp_as_mapping */
412 	0,										/* tp_hash  */
413 	0,										/* tp_call */
414 	0,										/* tp_str */
415 	0,										/* tp_getattro */
416 	0,										/* tp_setattro */
417 	0,										/* tp_as_buffer */
418 	Py_TPFLAGS_DEFAULT,						/* tp_flags */
419 	M_aud_DynamicMusic_doc,					/* tp_doc */
420 	0,										/* tp_traverse */
421 	0,										/* tp_clear */
422 	0,										/* tp_richcompare */
423 	0,										/* tp_weaklistoffset */
424 	0,										/* tp_iter */
425 	0,										/* tp_iternext */
426 	DynamicMusic_methods,					/* tp_methods */
427 	0,										/* tp_members */
428 	DynamicMusic_properties,				/* tp_getset */
429 	0,										/* tp_base */
430 	0,										/* tp_dict */
431 	0,										/* tp_descr_get */
432 	0,										/* tp_descr_set */
433 	0,										/* tp_dictoffset */
434 	0,										/* tp_init */
435 	0,										/* tp_alloc */
436 	DynamicMusic_new,						/* tp_new */
437 };
438 
DynamicMusic_empty()439 AUD_API PyObject* DynamicMusic_empty()
440 {
441 	return DynamicMusicType.tp_alloc(&DynamicMusicType, 0);
442 }
443 
444 
checkDynamicMusic(PyObject * dynamicMusic)445 AUD_API DynamicMusicP* checkDynamicMusic(PyObject* dynamicMusic)
446 {
447 	if(!PyObject_TypeCheck(dynamicMusic, &DynamicMusicType))
448 	{
449 		PyErr_SetString(PyExc_TypeError, "Object is not of type DynamicMusic!");
450 		return nullptr;
451 	}
452 
453 	return (DynamicMusicP*)dynamicMusic;
454 }
455 
456 
initializeDynamicMusic()457 bool initializeDynamicMusic()
458 {
459 	return PyType_Ready(&DynamicMusicType) >= 0;
460 }
461 
462 
addDynamicMusicToModule(PyObject * module)463 void addDynamicMusicToModule(PyObject* module)
464 {
465 	Py_INCREF(&DynamicMusicType);
466 	PyModule_AddObject(module, "DynamicMusic", (PyObject *)&DynamicMusicType);
467 }
468