Audaspace:
[blender.git] / intern / audaspace / Python / AUD_PyAPI.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * Copyright 2009-2011 Jörg Hermann Müller
5  *
6  * This file is part of AudaSpace.
7  *
8  * Audaspace is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * AudaSpace is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Audaspace; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file audaspace/Python/AUD_PyAPI.cpp
26  *  \ingroup audpython
27  */
28
29
30 #include "AUD_PyAPI.h"
31 #include <structmember.h>
32
33 #include "AUD_I3DDevice.h"
34 #include "AUD_I3DHandle.h"
35 #include "AUD_NULLDevice.h"
36 #include "AUD_DelayFactory.h"
37 #include "AUD_DoubleFactory.h"
38 #include "AUD_FaderFactory.h"
39 #include "AUD_HighpassFactory.h"
40 #include "AUD_LimiterFactory.h"
41 #include "AUD_LoopFactory.h"
42 #include "AUD_LowpassFactory.h"
43 #include "AUD_PingPongFactory.h"
44 #include "AUD_PitchFactory.h"
45 #include "AUD_ReverseFactory.h"
46 #include "AUD_SinusFactory.h"
47 #include "AUD_FileFactory.h"
48 #include "AUD_SquareFactory.h"
49 #include "AUD_StreamBufferFactory.h"
50 #include "AUD_SuperposeFactory.h"
51 #include "AUD_VolumeFactory.h"
52 #include "AUD_IIRFilterFactory.h"
53
54 #ifdef WITH_SDL
55 #include "AUD_SDLDevice.h"
56 #endif
57
58 #ifdef WITH_OPENAL
59 #include "AUD_OpenALDevice.h"
60 #endif
61
62 #ifdef WITH_JACK
63 #include "AUD_JackDevice.h"
64 #endif
65
66 // ====================================================================
67
68 typedef enum
69 {
70         AUD_DEVICE_NULL = 0,
71         AUD_DEVICE_OPENAL,
72         AUD_DEVICE_SDL,
73         AUD_DEVICE_JACK,
74         AUD_DEVICE_READ,
75 } AUD_DeviceTypes;
76
77 // ====================================================================
78
79 #define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, #name, name)
80
81 // ====================================================================
82
83 static PyObject *AUDError;
84
85 static const char* device_not_3d_error = "Device is not a 3D device!";
86
87 // ====================================================================
88
89 static void
90 Factory_dealloc(Factory* self)
91 {
92         if(self->factory)
93                 delete reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory);
94         Py_XDECREF(self->child_list);
95         Py_TYPE(self)->tp_free((PyObject *)self);
96 }
97
98 static PyObject *
99 Factory_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
100 {
101         Factory *self;
102
103         self = (Factory*)type->tp_alloc(type, 0);
104         if(self != NULL)
105         {
106                 static const char *kwlist[] = {"filename", NULL};
107                 const char* filename = NULL;
108
109                 if(!PyArg_ParseTupleAndKeywords(args, kwds, "s:Factory", const_cast<char**>(kwlist), &filename))
110                 {
111                         Py_DECREF(self);
112                         return NULL;
113                 }
114
115                 try
116                 {
117                         self->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_FileFactory(filename));
118                 }
119                 catch(AUD_Exception& e)
120                 {
121                         Py_DECREF(self);
122                         PyErr_SetString(AUDError, e.str);
123                         return NULL;
124                 }
125         }
126
127         return (PyObject *)self;
128 }
129
130 PyDoc_STRVAR(M_aud_Factory_sine_doc,
131                          "sine(frequency, rate=44100)\n\n"
132                          "Creates a sine factory which plays a sine wave.\n\n"
133                          ":arg frequency: The frequency of the sine wave in Hz.\n"
134                          ":type frequency: float\n"
135                          ":arg rate: The sampling rate in Hz. It's recommended to set this "
136                          "value to the playback device's samling rate to avoid resamping.\n"
137                          ":type rate: int\n"
138                          ":return: The created :class:`Factory` object.\n"
139                          ":rtype: :class:`Factory`");
140
141 static PyObject *
142 Factory_sine(PyTypeObject* type, PyObject *args)
143 {
144         float frequency;
145         double rate = 44100;
146
147         if(!PyArg_ParseTuple(args, "f|d:sine", &frequency, &rate))
148                 return NULL;
149
150         Factory *self;
151
152         self = (Factory*)type->tp_alloc(type, 0);
153         if(self != NULL)
154         {
155                 try
156                 {
157                         self->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_SinusFactory(frequency, (AUD_SampleRate)rate));
158                 }
159                 catch(AUD_Exception& e)
160                 {
161                         Py_DECREF(self);
162                         PyErr_SetString(AUDError, e.str);
163                         return NULL;
164                 }
165         }
166
167         return (PyObject *)self;
168 }
169
170 PyDoc_STRVAR(M_aud_Factory_file_doc,
171                          "file(filename)\n\n"
172                          "Creates a factory object of a sound file.\n\n"
173                          ":arg filename: Path of the file.\n"
174                          ":type filename: string\n"
175                          ":return: The created :class:`Factory` object.\n"
176                          ":rtype: :class:`Factory`\n\n"
177                          ".. warning:: If the file doesn't exist or can't be read you will "
178                          "not get an exception immediately, but when you try to start "
179                          "playback of that factory.");
180
181 static PyObject *
182 Factory_file(PyTypeObject* type, PyObject *args)
183 {
184         const char* filename = NULL;
185
186         if(!PyArg_ParseTuple(args, "s:file", &filename))
187                 return NULL;
188
189         Factory *self;
190
191         self = (Factory*)type->tp_alloc(type, 0);
192         if(self != NULL)
193         {
194                 try
195                 {
196                         self->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_FileFactory(filename));
197                 }
198                 catch(AUD_Exception& e)
199                 {
200                         Py_DECREF(self);
201                         PyErr_SetString(AUDError, e.str);
202                         return NULL;
203                 }
204         }
205
206         return (PyObject *)self;
207 }
208
209 PyDoc_STRVAR(M_aud_Factory_lowpass_doc,
210                          "lowpass(frequency, Q=0.5)\n\n"
211                          "Creates a second order lowpass filter based on the transfer "
212                          "function H(s) = 1 / (s^2 + s/Q + 1)\n\n"
213                          ":arg frequency: The cut off trequency of the lowpass.\n"
214                          ":type frequency: float\n"
215                          ":arg Q: Q factor of the lowpass.\n"
216                          ":type Q: float\n"
217                          ":return: The created :class:`Factory` object.\n"
218                          ":rtype: :class:`Factory`");
219
220 static PyObject *
221 Factory_lowpass(Factory* self, PyObject *args)
222 {
223         float frequency;
224         float Q = 0.5;
225
226         if(!PyArg_ParseTuple(args, "f|f:lowpass", &frequency, &Q))
227                 return NULL;
228
229         PyTypeObject* type = Py_TYPE(self);
230         Factory *parent = (Factory*)type->tp_alloc(type, 0);
231
232         if(parent != NULL)
233         {
234                 Py_INCREF(self);
235                 parent->child_list = (PyObject *)self;
236
237                 try
238                 {
239                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_LowpassFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), frequency, Q));
240                 }
241                 catch(AUD_Exception& e)
242                 {
243                         Py_DECREF(parent);
244                         PyErr_SetString(AUDError, e.str);
245                         return NULL;
246                 }
247         }
248
249         return (PyObject *)parent;
250 }
251
252 PyDoc_STRVAR(M_aud_Factory_delay_doc,
253                          "delay(time)\n\n"
254                          "Delays by playing adding silence in front of the other factory's "
255                          "data.\n\n"
256                          ":arg time: How many seconds of silence should be added before "
257                          "the factory.\n"
258                          ":type time: float\n"
259                          ":return: The created :class:`Factory` object.\n"
260                          ":rtype: :class:`Factory`");
261
262 static PyObject *
263 Factory_delay(Factory* self, PyObject *args)
264 {
265         float delay;
266
267         if(!PyArg_ParseTuple(args, "f:delay", &delay))
268                 return NULL;
269
270         PyTypeObject* type = Py_TYPE(self);
271         Factory *parent = (Factory*)type->tp_alloc(type, 0);
272
273         if(parent != NULL)
274         {
275                 Py_INCREF(self);
276                 parent->child_list = (PyObject *)self;
277
278                 try
279                 {
280                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_DelayFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), delay));
281                 }
282                 catch(AUD_Exception& e)
283                 {
284                         Py_DECREF(parent);
285                         PyErr_SetString(AUDError, e.str);
286                         return NULL;
287                 }
288         }
289
290         return (PyObject *)parent;
291 }
292
293 PyDoc_STRVAR(M_aud_Factory_join_doc,
294                          "join(factory)\n\n"
295                          "Plays two factories in sequence.\n\n"
296                          ":arg factory: The factory to play second.\n"
297                          ":type factory: :class:`Factory`\n"
298                          ":return: The created :class:`Factory` object.\n"
299                          ":rtype: :class:`Factory`\n\n"
300                          ".. note:: The two factories have to have the same specifications "
301                          "(channels and samplerate).");
302
303 static PyObject *
304 Factory_join(Factory* self, PyObject *object)
305 {
306         PyTypeObject* type = Py_TYPE(self);
307
308         if(!PyObject_TypeCheck(object, type))
309         {
310                 PyErr_SetString(PyExc_TypeError, "Object has to be of type Factory!");
311                 return NULL;
312         }
313
314         Factory *parent;
315         Factory *child = (Factory*)object;
316
317         parent = (Factory*)type->tp_alloc(type, 0);
318         if(parent != NULL)
319         {
320                 parent->child_list = Py_BuildValue("(OO)", self, object);
321
322                 try
323                 {
324                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_DoubleFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), *reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(child->factory)));
325                 }
326                 catch(AUD_Exception& e)
327                 {
328                         Py_DECREF(parent);
329                         PyErr_SetString(AUDError, e.str);
330                         return NULL;
331                 }
332         }
333
334         return (PyObject *)parent;
335 }
336
337 PyDoc_STRVAR(M_aud_Factory_highpass_doc,
338                          "highpass(frequency, Q=0.5)\n\n"
339                          "Creates a second order highpass filter based on the transfer "
340                          "function H(s) = s^2 / (s^2 + s/Q + 1)\n\n"
341                          ":arg frequency: The cut off trequency of the highpass.\n"
342                          ":type frequency: float\n"
343                          ":arg Q: Q factor of the lowpass.\n"
344                          ":type Q: float\n"
345                          ":return: The created :class:`Factory` object.\n"
346                          ":rtype: :class:`Factory`");
347
348 static PyObject *
349 Factory_highpass(Factory* self, PyObject *args)
350 {
351         float frequency;
352         float Q = 0.5;
353
354         if(!PyArg_ParseTuple(args, "f|f:highpass", &frequency, &Q))
355                 return NULL;
356
357         PyTypeObject* type = Py_TYPE(self);
358         Factory *parent = (Factory*)type->tp_alloc(type, 0);
359
360         if(parent != NULL)
361         {
362                 Py_INCREF(self);
363                 parent->child_list = (PyObject *)self;
364
365                 try
366                 {
367                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_HighpassFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), frequency, Q));
368                 }
369                 catch(AUD_Exception& e)
370                 {
371                         Py_DECREF(parent);
372                         PyErr_SetString(AUDError, e.str);
373                         return NULL;
374                 }
375         }
376
377         return (PyObject *)parent;
378 }
379
380 PyDoc_STRVAR(M_aud_Factory_limit_doc,
381                          "limit(start, end)\n\n"
382                          "Limits a factory within a specific start and end time.\n\n"
383                          ":arg start: Start time in seconds.\n"
384                          ":type start: float\n"
385                          ":arg end: End time in seconds.\n"
386                          ":type end: float\n"
387                          ":return: The created :class:`Factory` object.\n"
388                          ":rtype: :class:`Factory`");
389
390 static PyObject *
391 Factory_limit(Factory* self, PyObject *args)
392 {
393         float start, end;
394
395         if(!PyArg_ParseTuple(args, "ff:limit", &start, &end))
396                 return NULL;
397
398         PyTypeObject* type = Py_TYPE(self);
399         Factory *parent = (Factory*)type->tp_alloc(type, 0);
400
401         if(parent != NULL)
402         {
403                 Py_INCREF(self);
404                 parent->child_list = (PyObject *)self;
405
406                 try
407                 {
408                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_LimiterFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), start, end));
409                 }
410                 catch(AUD_Exception& e)
411                 {
412                         Py_DECREF(parent);
413                         PyErr_SetString(AUDError, e.str);
414                         return NULL;
415                 }
416         }
417
418         return (PyObject *)parent;
419 }
420
421 PyDoc_STRVAR(M_aud_Factory_pitch_doc,
422                          "pitch(factor)\n\n"
423                          "Changes the pitch of a factory with a specific factor.\n\n"
424                          ":arg factor: The factor to change the pitch with.\n"
425                          ":type factor: float\n"
426                          ":return: The created :class:`Factory` object.\n"
427                          ":rtype: :class:`Factory`\n\n"
428                          ".. note:: This is done by changing the sample rate of the "
429                          "underlying factory, which has to be an integer, so the factor "
430                          "value rounded and the factor may not be 100 % accurate.\n\n"
431                          ".. note:: This is a filter function, you might consider using "
432                          ":attr:`Handle.pitch` instead.");
433
434 static PyObject *
435 Factory_pitch(Factory* self, PyObject *args)
436 {
437         float factor;
438
439         if(!PyArg_ParseTuple(args, "f:pitch", &factor))
440                 return NULL;
441
442         PyTypeObject* type = Py_TYPE(self);
443         Factory *parent = (Factory*)type->tp_alloc(type, 0);
444
445         if(parent != NULL)
446         {
447                 Py_INCREF(self);
448                 parent->child_list = (PyObject *)self;
449
450                 try
451                 {
452                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_PitchFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), factor));
453                 }
454                 catch(AUD_Exception& e)
455                 {
456                         Py_DECREF(parent);
457                         PyErr_SetString(AUDError, e.str);
458                         return NULL;
459                 }
460         }
461
462         return (PyObject *)parent;
463 }
464
465 PyDoc_STRVAR(M_aud_Factory_volume_doc,
466                          "volume(volume)\n\n"
467                          "Changes the volume of a factory.\n\n"
468                          ":arg volume: The new volume..\n"
469                          ":type volume: float\n"
470                          ":return: The created :class:`Factory` object.\n"
471                          ":rtype: :class:`Factory`\n\n"
472                          ".. note:: Should be in the range [0, 1] to avoid clipping.\n\n"
473                          ".. note:: This is a filter function, you might consider using "
474                          ":attr:`Handle.volume` instead.");
475
476 static PyObject *
477 Factory_volume(Factory* self, PyObject *args)
478 {
479         float volume;
480
481         if(!PyArg_ParseTuple(args, "f:volume", &volume))
482                 return NULL;
483
484         PyTypeObject* type = Py_TYPE(self);
485         Factory *parent = (Factory*)type->tp_alloc(type, 0);
486
487         if(parent != NULL)
488         {
489                 Py_INCREF(self);
490                 parent->child_list = (PyObject *)self;
491
492                 try
493                 {
494                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_VolumeFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), volume));
495                 }
496                 catch(AUD_Exception& e)
497                 {
498                         Py_DECREF(parent);
499                         PyErr_SetString(AUDError, e.str);
500                         return NULL;
501                 }
502         }
503
504         return (PyObject *)parent;
505 }
506
507 PyDoc_STRVAR(M_aud_Factory_fadein_doc,
508                          "fadein(start, length)\n\n"
509                          "Fades a factory in by raising the volume linearly in the given "
510                          "time interval.\n\n"
511                          ":arg start: Time in seconds when the fading should start.\n"
512                          ":type start: float\n"
513                          ":arg length: Time in seconds how long the fading should last.\n"
514                          ":type length: float\n"
515                          ":return: The created :class:`Factory` object.\n"
516                          ":rtype: :class:`Factory`\n\n"
517                          ".. note:: Before the fade starts it plays silence.");
518
519 static PyObject *
520 Factory_fadein(Factory* self, PyObject *args)
521 {
522         float start, length;
523
524         if(!PyArg_ParseTuple(args, "ff:fadein", &start, &length))
525                 return NULL;
526
527         PyTypeObject* type = Py_TYPE(self);
528         Factory *parent = (Factory*)type->tp_alloc(type, 0);
529
530         if(parent != NULL)
531         {
532                 Py_INCREF(self);
533                 parent->child_list = (PyObject *)self;
534
535                 try
536                 {
537                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_FaderFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), AUD_FADE_IN, start, length));
538                 }
539                 catch(AUD_Exception& e)
540                 {
541                         Py_DECREF(parent);
542                         PyErr_SetString(AUDError, e.str);
543                         return NULL;
544                 }
545         }
546
547         return (PyObject *)parent;
548 }
549
550 PyDoc_STRVAR(M_aud_Factory_fadeout_doc,
551                          "fadeout(start, length)\n\n"
552                          "Fades a factory in by lowering the volume linearly in the given "
553                          "time interval.\n\n"
554                          ":arg start: Time in seconds when the fading should start.\n"
555                          ":type start: float\n"
556                          ":arg length: Time in seconds how long the fading should last.\n"
557                          ":type length: float\n"
558                          ":return: The created :class:`Factory` object.\n"
559                          ":rtype: :class:`Factory`\n\n"
560                          ".. note:: After the fade this factory plays silence, so that "
561                          "the length of the factory is not altered.");
562
563 static PyObject *
564 Factory_fadeout(Factory* self, PyObject *args)
565 {
566         float start, length;
567
568         if(!PyArg_ParseTuple(args, "ff:fadeout", &start, &length))
569                 return NULL;
570
571         PyTypeObject* type = Py_TYPE(self);
572         Factory *parent = (Factory*)type->tp_alloc(type, 0);
573
574         if(parent != NULL)
575         {
576                 Py_INCREF(self);
577                 parent->child_list = (PyObject *)self;
578
579                 try
580                 {
581                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_FaderFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), AUD_FADE_OUT, start, length));
582                 }
583                 catch(AUD_Exception& e)
584                 {
585                         Py_DECREF(parent);
586                         PyErr_SetString(AUDError, e.str);
587                         return NULL;
588                 }
589         }
590
591         return (PyObject *)parent;
592 }
593
594 PyDoc_STRVAR(M_aud_Factory_loop_doc,
595                          "loop(count)\n\n"
596                          "Loops a factory.\n\n"
597                          ":arg count: How often the factory should be looped. "
598                          "Negative values mean endlessly.\n"
599                          ":type count: integer\n"
600                          ":return: The created :class:`Factory` object.\n"
601                          ":rtype: :class:`Factory`\n\n"
602                          ".. note:: This is a filter function, you might consider using "
603                          ":attr:`Handle.loop_count` instead.");
604
605 static PyObject *
606 Factory_loop(Factory* self, PyObject *args)
607 {
608         int loop;
609
610         if(!PyArg_ParseTuple(args, "i:loop", &loop))
611                 return NULL;
612
613         PyTypeObject* type = Py_TYPE(self);
614         Factory *parent = (Factory*)type->tp_alloc(type, 0);
615
616         if(parent != NULL)
617         {
618                 Py_INCREF(self);
619                 parent->child_list = (PyObject *)self;
620
621                 try
622                 {
623                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_LoopFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), loop));
624                 }
625                 catch(AUD_Exception& e)
626                 {
627                         Py_DECREF(parent);
628                         PyErr_SetString(AUDError, e.str);
629                         return NULL;
630                 }
631         }
632
633         return (PyObject *)parent;
634 }
635
636 PyDoc_STRVAR(M_aud_Factory_mix_doc,
637                          "mix(factory)\n\n"
638                          "Mixes two factories.\n\n"
639                          ":arg factory: The factory to mix over the other.\n"
640                          ":type factory: :class:`Factory`\n"
641                          ":return: The created :class:`Factory` object.\n"
642                          ":rtype: :class:`Factory`\n\n"
643                          ".. note:: The two factories have to have the same specifications "
644                          "(channels and samplerate).");
645
646 static PyObject *
647 Factory_mix(Factory* self, PyObject *object)
648 {
649         PyTypeObject* type = Py_TYPE(self);
650
651         if(!PyObject_TypeCheck(object, type))
652         {
653                 PyErr_SetString(PyExc_TypeError, "Object is not of type Factory!");
654                 return NULL;
655         }
656
657         Factory *parent = (Factory*)type->tp_alloc(type, 0);
658         Factory *child = (Factory*)object;
659
660         if(parent != NULL)
661         {
662                 parent->child_list = Py_BuildValue("(OO)", self, object);
663
664                 try
665                 {
666                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_SuperposeFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), *reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(child->factory)));
667                 }
668                 catch(AUD_Exception& e)
669                 {
670                         Py_DECREF(parent);
671                         PyErr_SetString(AUDError, e.str);
672                         return NULL;
673                 }
674         }
675
676         return (PyObject *)parent;
677 }
678
679 PyDoc_STRVAR(M_aud_Factory_pingpong_doc,
680                          "pingpong()\n\n"
681                          "Plays a factory forward and then backward.\n"
682                          "This is like joining a factory with its reverse.\n\n"
683                          ":return: The created :class:`Factory` object.\n"
684                          ":rtype: :class:`Factory`");
685
686 static PyObject *
687 Factory_pingpong(Factory* self)
688 {
689         PyTypeObject* type = Py_TYPE(self);
690         Factory *parent = (Factory*)type->tp_alloc(type, 0);
691
692         if(parent != NULL)
693         {
694                 Py_INCREF(self);
695                 parent->child_list = (PyObject *)self;
696
697                 try
698                 {
699                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_PingPongFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory)));
700                 }
701                 catch(AUD_Exception& e)
702                 {
703                         Py_DECREF(parent);
704                         PyErr_SetString(AUDError, e.str);
705                         return NULL;
706                 }
707         }
708
709         return (PyObject *)parent;
710 }
711
712 PyDoc_STRVAR(M_aud_Factory_reverse_doc,
713                          "reverse()\n\n"
714                          "Plays a factory reversed.\n\n"
715                          ":return: The created :class:`Factory` object.\n"
716                          ":rtype: :class:`Factory`\n\n"
717                          ".. note:: The factory has to have a finite length and has to be "
718                          "seekable. It's recommended to use this only with factories     with "
719                          "fast and accurate seeking, which is not true for encoded audio "
720                          "files, such ones should be buffered using :meth:`buffer` before "
721                          "being played reversed.\n\n"
722                          ".. warning:: If seeking is not accurate in the underlying factory "
723                          "you'll likely hear skips/jumps/cracks.");
724
725 static PyObject *
726 Factory_reverse(Factory* self)
727 {
728         PyTypeObject* type = Py_TYPE(self);
729         Factory *parent = (Factory*)type->tp_alloc(type, 0);
730
731         if(parent != NULL)
732         {
733                 Py_INCREF(self);
734                 parent->child_list = (PyObject *)self;
735
736                 try
737                 {
738                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_ReverseFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory)));
739                 }
740                 catch(AUD_Exception& e)
741                 {
742                         Py_DECREF(parent);
743                         PyErr_SetString(AUDError, e.str);
744                         return NULL;
745                 }
746         }
747
748         return (PyObject *)parent;
749 }
750
751 PyDoc_STRVAR(M_aud_Factory_buffer_doc,
752                          "buffer()\n\n"
753                          "Buffers a factory into RAM.\n"
754                          "This saves CPU usage needed for decoding and file access if the "
755                          "underlying factory reads from a file on the harddisk, but it "
756                          "consumes a lot of memory.\n\n"
757                          ":return: The created :class:`Factory` object.\n"
758                          ":rtype: :class:`Factory`\n\n"
759                          ".. note:: Only known-length factories can be buffered.\n\n"
760                          ".. warning:: Raw PCM data needs a lot of space, only buffer "
761                          "short factories.");
762
763 static PyObject *
764 Factory_buffer(Factory* self)
765 {
766         PyTypeObject* type = Py_TYPE(self);
767         Factory *parent = (Factory*)type->tp_alloc(type, 0);
768
769         if(parent != NULL)
770         {
771                 try
772                 {
773                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_StreamBufferFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory)));
774                 }
775                 catch(AUD_Exception& e)
776                 {
777                         Py_DECREF(parent);
778                         PyErr_SetString(AUDError, e.str);
779                         return NULL;
780                 }
781         }
782
783         return (PyObject *)parent;
784 }
785
786 PyDoc_STRVAR(M_aud_Factory_square_doc,
787                          "square(threshold = 0)\n\n"
788                          "Makes a square wave out of an audio wave by setting all samples "
789                          "with a amplitude >= threshold to 1, all <= -threshold to -1 and "
790                          "all between to 0.\n\n"
791                          ":arg threshold: Threshold value over which an amplitude counts "
792                          "non-zero.\n"
793                          ":type threshold: float\n"
794                          ":return: The created :class:`Factory` object.\n"
795                          ":rtype: :class:`Factory`");
796
797 static PyObject *
798 Factory_square(Factory* self, PyObject *args)
799 {
800         float threshold = 0;
801
802         if(!PyArg_ParseTuple(args, "|f:square", &threshold))
803                 return NULL;
804
805         PyTypeObject* type = Py_TYPE(self);
806         Factory *parent = (Factory*)type->tp_alloc(type, 0);
807
808         if(parent != NULL)
809         {
810                 Py_INCREF(self);
811                 parent->child_list = (PyObject *)self;
812
813                 try
814                 {
815                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_SquareFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), threshold));
816                 }
817                 catch(AUD_Exception& e)
818                 {
819                         Py_DECREF(parent);
820                         PyErr_SetString(AUDError, e.str);
821                         return NULL;
822                 }
823         }
824
825         return (PyObject *)parent;
826 }
827
828 PyDoc_STRVAR(M_aud_Factory_filter_doc,
829                          "filter(b, a = (1))\n\n"
830                          "Filters a factory with the supplied IIR filter coefficients.\n"
831                          "Without the second parameter you'll get a FIR filter.\n"
832                          "If the first value of the a sequence is 0 it will be set to 1 "
833                          "automatically.\n"
834                          "If the first value of the a sequence is neither 0 nor 1, all "
835                          "filter coefficients will be scaled by this value so that it is 1 "
836                          "in the end, you don't have to scale yourself.\n\n"
837                          ":arg b: The nominator filter coefficients.\n"
838                          ":type b: sequence of float\n"
839                          ":arg a: The denominator filter coefficients.\n"
840                          ":type a: sequence of float\n"
841                          ":return: The created :class:`Factory` object.\n"
842                          ":rtype: :class:`Factory`");
843
844 static PyObject *
845 Factory_filter(Factory* self, PyObject *args)
846 {
847         PyObject *py_b;
848         PyObject *py_a = NULL;
849         Py_ssize_t py_a_len;
850         Py_ssize_t py_b_len;
851
852         if(!PyArg_ParseTuple(args, "O|O:filter", &py_b, &py_a))
853                 return NULL;
854
855         if(!PySequence_Check(py_b) || (py_a != NULL && !PySequence_Check(py_a)))
856         {
857                 PyErr_SetString(PyExc_TypeError, "Parameter is not a sequence!");
858                 return NULL;
859         }
860
861         py_a_len= py_a ? PySequence_Size(py_a) : 0;
862         py_b_len= PySequence_Size(py_b);
863
864         if(!py_b_len || ((py_a != NULL) && !py_b_len))
865         {
866                 PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!");
867                 return NULL;
868         }
869
870         std::vector<float> a, b;
871         PyObject *py_value;
872         float value;
873
874         for(Py_ssize_t i = 0; i < py_b_len; i++)
875         {
876                 py_value = PySequence_GetItem(py_b, i);
877                 value= (float)PyFloat_AsDouble(py_value);
878                 Py_DECREF(py_value);
879
880                 if (value==-1.0f && PyErr_Occurred()) {
881                         return NULL;
882                 }
883
884                 b.push_back(value);
885         }
886
887         if(py_a)
888         {
889                 for(Py_ssize_t i = 0; i < py_a_len; i++)
890                 {
891                         py_value = PySequence_GetItem(py_a, i);
892                         value= (float)PyFloat_AsDouble(py_value);
893                         Py_DECREF(py_value);
894
895                         if (value==-1.0f && PyErr_Occurred()) {
896                                 return NULL;
897                         }
898
899                         a.push_back(value);
900                 }
901
902                 if(a[0] == 0)
903                         a[0] = 1;
904         }
905         else
906                 a.push_back(1);
907
908         PyTypeObject* type = Py_TYPE(self);
909         Factory *parent = (Factory*)type->tp_alloc(type, 0);
910
911         if(parent != NULL)
912         {
913                 Py_INCREF(self);
914                 parent->child_list = (PyObject *)self;
915
916                 try
917                 {
918                         parent->factory = new boost::shared_ptr<AUD_IFactory>(new AUD_IIRFilterFactory(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(self->factory), b, a));
919                 }
920                 catch(AUD_Exception& e)
921                 {
922                         Py_DECREF(parent);
923                         PyErr_SetString(AUDError, e.str);
924                         return NULL;
925                 }
926         }
927
928         return (PyObject *)parent;
929 }
930
931 static PyMethodDef Factory_methods[] = {
932         {"sine", (PyCFunction)Factory_sine, METH_VARARGS | METH_CLASS,
933          M_aud_Factory_sine_doc
934         },
935         {"file", (PyCFunction)Factory_file, METH_VARARGS | METH_CLASS,
936          M_aud_Factory_file_doc
937         },
938         {"lowpass", (PyCFunction)Factory_lowpass, METH_VARARGS,
939          M_aud_Factory_lowpass_doc
940         },
941         {"delay", (PyCFunction)Factory_delay, METH_VARARGS,
942          M_aud_Factory_delay_doc
943         },
944         {"join", (PyCFunction)Factory_join, METH_O,
945          M_aud_Factory_join_doc
946         },
947         {"highpass", (PyCFunction)Factory_highpass, METH_VARARGS,
948          M_aud_Factory_highpass_doc
949         },
950         {"limit", (PyCFunction)Factory_limit, METH_VARARGS,
951          M_aud_Factory_limit_doc
952         },
953         {"pitch", (PyCFunction)Factory_pitch, METH_VARARGS,
954          M_aud_Factory_pitch_doc
955         },
956         {"volume", (PyCFunction)Factory_volume, METH_VARARGS,
957          M_aud_Factory_volume_doc
958         },
959         {"fadein", (PyCFunction)Factory_fadein, METH_VARARGS,
960          M_aud_Factory_fadein_doc
961         },
962         {"fadeout", (PyCFunction)Factory_fadeout, METH_VARARGS,
963          M_aud_Factory_fadeout_doc
964         },
965         {"loop", (PyCFunction)Factory_loop, METH_VARARGS,
966          M_aud_Factory_loop_doc
967         },
968         {"mix", (PyCFunction)Factory_mix, METH_O,
969          M_aud_Factory_mix_doc
970         },
971         {"pingpong", (PyCFunction)Factory_pingpong, METH_NOARGS,
972          M_aud_Factory_pingpong_doc
973         },
974         {"reverse", (PyCFunction)Factory_reverse, METH_NOARGS,
975          M_aud_Factory_reverse_doc
976         },
977         {"buffer", (PyCFunction)Factory_buffer, METH_NOARGS,
978          M_aud_Factory_buffer_doc
979         },
980         {"square", (PyCFunction)Factory_square, METH_VARARGS,
981          M_aud_Factory_square_doc
982         },
983         {"filter", (PyCFunction)Factory_filter, METH_VARARGS,
984          M_aud_Factory_filter_doc
985         },
986         {NULL}  /* Sentinel */
987 };
988
989 PyDoc_STRVAR(M_aud_Factory_doc,
990                          "Factory objects are immutable and represent a sound that can be "
991                          "played simultaneously multiple times. They are called factories "
992                          "because they create reader objects internally that are used for "
993                          "playback.");
994
995 static PyTypeObject FactoryType = {
996         PyVarObject_HEAD_INIT(NULL, 0)
997         "aud.Factory",               /* tp_name */
998         sizeof(Factory),             /* tp_basicsize */
999         0,                         /* tp_itemsize */
1000         (destructor)Factory_dealloc, /* tp_dealloc */
1001         0,                         /* tp_print */
1002         0,                         /* tp_getattr */
1003         0,                         /* tp_setattr */
1004         0,                         /* tp_reserved */
1005         0,                         /* tp_repr */
1006         0,                         /* tp_as_number */
1007         0,                         /* tp_as_sequence */
1008         0,                         /* tp_as_mapping */
1009         0,                         /* tp_hash  */
1010         0,                         /* tp_call */
1011         0,                         /* tp_str */
1012         0,                         /* tp_getattro */
1013         0,                         /* tp_setattro */
1014         0,                         /* tp_as_buffer */
1015         Py_TPFLAGS_DEFAULT,        /* tp_flags */
1016         M_aud_Factory_doc,           /* tp_doc */
1017         0,                                 /* tp_traverse */
1018         0,                                 /* tp_clear */
1019         0,                                 /* tp_richcompare */
1020         0,                                 /* tp_weaklistoffset */
1021         0,                                 /* tp_iter */
1022         0,                                 /* tp_iternext */
1023         Factory_methods,             /* tp_methods */
1024         0,                         /* tp_members */
1025         0,                         /* tp_getset */
1026         0,                         /* tp_base */
1027         0,                         /* tp_dict */
1028         0,                         /* tp_descr_get */
1029         0,                         /* tp_descr_set */
1030         0,                         /* tp_dictoffset */
1031         0,                         /* tp_init */
1032         0,                         /* tp_alloc */
1033         Factory_new,                 /* tp_new */
1034 };
1035
1036 // ========== Handle ==================================================
1037
1038 static void
1039 Handle_dealloc(Handle* self)
1040 {
1041         if(self->handle)
1042                 delete reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle);
1043         Py_TYPE(self)->tp_free((PyObject *)self);
1044 }
1045
1046 PyDoc_STRVAR(M_aud_Handle_pause_doc,
1047                          "pause()\n\n"
1048                          "Pauses playback.\n\n"
1049                          ":return: Whether the action succeeded.\n"
1050                          ":rtype: bool");
1051
1052 static PyObject *
1053 Handle_pause(Handle *self)
1054 {
1055         try
1056         {
1057                 return PyBool_FromLong((long)(*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->pause());
1058         }
1059         catch(AUD_Exception& e)
1060         {
1061                 PyErr_SetString(AUDError, e.str);
1062                 return NULL;
1063         }
1064 }
1065
1066 PyDoc_STRVAR(M_aud_Handle_resume_doc,
1067                          "resume()\n\n"
1068                          "Resumes playback.\n\n"
1069                          ":return: Whether the action succeeded.\n"
1070                          ":rtype: bool");
1071
1072 static PyObject *
1073 Handle_resume(Handle *self)
1074 {
1075         try
1076         {
1077                 return PyBool_FromLong((long)(*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->resume());
1078         }
1079         catch(AUD_Exception& e)
1080         {
1081                 PyErr_SetString(AUDError, e.str);
1082                 return NULL;
1083         }
1084 }
1085
1086 PyDoc_STRVAR(M_aud_Handle_stop_doc,
1087                          "stop()\n\n"
1088                          "Stops playback.\n\n"
1089                          ":return: Whether the action succeeded.\n"
1090                          ":rtype: bool\n\n"
1091                          ".. note:: This makes the handle invalid.");
1092
1093 static PyObject *
1094 Handle_stop(Handle *self)
1095 {
1096         try
1097         {
1098                 return PyBool_FromLong((long)(*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->stop());
1099         }
1100         catch(AUD_Exception& e)
1101         {
1102                 PyErr_SetString(AUDError, e.str);
1103                 return NULL;
1104         }
1105 }
1106
1107 static PyMethodDef Handle_methods[] = {
1108         {"pause", (PyCFunction)Handle_pause, METH_NOARGS,
1109          M_aud_Handle_pause_doc
1110         },
1111         {"resume", (PyCFunction)Handle_resume, METH_NOARGS,
1112          M_aud_Handle_resume_doc
1113         },
1114         {"stop", (PyCFunction)Handle_stop, METH_NOARGS,
1115          M_aud_Handle_stop_doc
1116         },
1117         {NULL}  /* Sentinel */
1118 };
1119
1120 PyDoc_STRVAR(M_aud_Handle_position_doc,
1121                          "The playback position of the sound in seconds.");
1122
1123 static PyObject *
1124 Handle_get_position(Handle *self, void* nothing)
1125 {
1126         try
1127         {
1128                 return Py_BuildValue("f", (*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->getPosition());
1129         }
1130         catch(AUD_Exception& e)
1131         {
1132                 PyErr_SetString(AUDError, e.str);
1133                 return NULL;
1134         }
1135 }
1136
1137 static int
1138 Handle_set_position(Handle *self, PyObject *args, void* nothing)
1139 {
1140         float position;
1141
1142         if(!PyArg_Parse(args, "f:position", &position))
1143                 return -1;
1144
1145         try
1146         {
1147                 if((*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->seek(position))
1148                         return 0;
1149                 PyErr_SetString(AUDError, "Couldn't seek the sound!");
1150         }
1151         catch(AUD_Exception& e)
1152         {
1153                 PyErr_SetString(AUDError, e.str);
1154         }
1155
1156         return -1;
1157 }
1158
1159 PyDoc_STRVAR(M_aud_Handle_keep_doc,
1160                          "Whether the sound should be kept paused in the device when its "
1161                          "end is reached.\n"
1162                          "This can be used to seek the sound to some position and start "
1163                          "playback again.\n\n"
1164                          ".. warning:: If this is set to true and you forget stopping this "
1165                          "equals a memory leak as the handle exists until the device is "
1166                          "destroyed.");
1167
1168 static PyObject *
1169 Handle_get_keep(Handle *self, void* nothing)
1170 {
1171         try
1172         {
1173                 return PyBool_FromLong((long)(*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->getKeep());
1174         }
1175         catch(AUD_Exception& e)
1176         {
1177                 PyErr_SetString(AUDError, e.str);
1178                 return NULL;
1179         }
1180 }
1181
1182 static int
1183 Handle_set_keep(Handle *self, PyObject *args, void* nothing)
1184 {
1185         if(!PyBool_Check(args))
1186         {
1187                 PyErr_SetString(PyExc_TypeError, "keep is not a boolean!");
1188                 return -1;
1189         }
1190
1191         bool keep = args == Py_True;
1192
1193         try
1194         {
1195                 if((*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->setKeep(keep))
1196                         return 0;
1197                 PyErr_SetString(AUDError, "Couldn't set keep of the sound!");
1198         }
1199         catch(AUD_Exception& e)
1200         {
1201                 PyErr_SetString(AUDError, e.str);
1202         }
1203
1204         return -1;
1205 }
1206
1207 PyDoc_STRVAR(M_aud_Handle_status_doc,
1208                          "Whether the sound is playing, paused or stopped (=invalid).");
1209
1210 static PyObject *
1211 Handle_get_status(Handle *self, void* nothing)
1212 {
1213         try
1214         {
1215                 return PyBool_FromLong((long)(*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->getStatus());
1216         }
1217         catch(AUD_Exception& e)
1218         {
1219                 PyErr_SetString(AUDError, e.str);
1220                 return NULL;
1221         }
1222 }
1223
1224 PyDoc_STRVAR(M_aud_Handle_volume_doc,
1225                          "The volume of the sound.");
1226
1227 static PyObject *
1228 Handle_get_volume(Handle *self, void* nothing)
1229 {
1230         try
1231         {
1232                 return Py_BuildValue("f", (*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->getVolume());
1233         }
1234         catch(AUD_Exception& e)
1235         {
1236                 PyErr_SetString(AUDError, e.str);
1237                 return NULL;
1238         }
1239 }
1240
1241 static int
1242 Handle_set_volume(Handle *self, PyObject *args, void* nothing)
1243 {
1244         float volume;
1245
1246         if(!PyArg_Parse(args, "f:volume", &volume))
1247                 return -1;
1248
1249         try
1250         {
1251                 if((*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->setVolume(volume))
1252                         return 0;
1253                 PyErr_SetString(AUDError, "Couldn't set the sound volume!");
1254         }
1255         catch(AUD_Exception& e)
1256         {
1257                 PyErr_SetString(AUDError, e.str);
1258         }
1259
1260         return -1;
1261 }
1262
1263 PyDoc_STRVAR(M_aud_Handle_pitch_doc,
1264                          "The pitch of the sound.");
1265
1266 static PyObject *
1267 Handle_get_pitch(Handle *self, void* nothing)
1268 {
1269         try
1270         {
1271                 return Py_BuildValue("f", (*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->getPitch());
1272         }
1273         catch(AUD_Exception& e)
1274         {
1275                 PyErr_SetString(AUDError, e.str);
1276                 return NULL;
1277         }
1278 }
1279
1280 static int
1281 Handle_set_pitch(Handle *self, PyObject *args, void* nothing)
1282 {
1283         float pitch;
1284
1285         if(!PyArg_Parse(args, "f:pitch", &pitch))
1286                 return -1;
1287
1288         try
1289         {
1290                 if((*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->setPitch(pitch))
1291                         return 0;
1292                 PyErr_SetString(AUDError, "Couldn't set the sound pitch!");
1293         }
1294         catch(AUD_Exception& e)
1295         {
1296                 PyErr_SetString(AUDError, e.str);
1297         }
1298
1299         return -1;
1300 }
1301
1302 PyDoc_STRVAR(M_aud_Handle_loop_count_doc,
1303                          "The (remaining) loop count of the sound. A negative value indicates infinity.");
1304
1305 static PyObject *
1306 Handle_get_loop_count(Handle *self, void* nothing)
1307 {
1308         try
1309         {
1310                 return Py_BuildValue("i", (*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->getLoopCount());
1311         }
1312         catch(AUD_Exception& e)
1313         {
1314                 PyErr_SetString(AUDError, e.str);
1315                 return NULL;
1316         }
1317 }
1318
1319 static int
1320 Handle_set_loop_count(Handle *self, PyObject *args, void* nothing)
1321 {
1322         int loops;
1323
1324         if(!PyArg_Parse(args, "i:loop_count", &loops))
1325                 return -1;
1326
1327         try
1328         {
1329                 if((*reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle))->setLoopCount(loops))
1330                         return 0;
1331                 PyErr_SetString(AUDError, "Couldn't set the loop count!");
1332         }
1333         catch(AUD_Exception& e)
1334         {
1335                 PyErr_SetString(AUDError, e.str);
1336         }
1337
1338         return -1;
1339 }
1340
1341 PyDoc_STRVAR(M_aud_Handle_location_doc,
1342                          "The source's location in 3D space, a 3D tuple of floats.");
1343
1344 static PyObject *
1345 Handle_get_location(Handle *self, void* nothing)
1346 {
1347         try
1348         {
1349                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1350                 if(handle)
1351                 {
1352                         AUD_Vector3 v = handle->getSourceLocation();
1353                         return Py_BuildValue("(fff)", v.x(), v.y(), v.z());
1354                 }
1355                 else
1356                 {
1357                         PyErr_SetString(AUDError, device_not_3d_error);
1358                 }
1359         }
1360         catch(AUD_Exception& e)
1361         {
1362                 PyErr_SetString(AUDError, e.str);
1363         }
1364
1365         return NULL;
1366 }
1367
1368 static int
1369 Handle_set_location(Handle *self, PyObject *args, void* nothing)
1370 {
1371         float x, y, z;
1372
1373         if(!PyArg_Parse(args, "(fff):location", &x, &y, &z))
1374                 return -1;
1375
1376         try
1377         {
1378                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1379                 if(handle)
1380                 {
1381                         AUD_Vector3 location(x, y, z);
1382                         if(handle->setSourceLocation(location))
1383                                 return 0;
1384                         PyErr_SetString(AUDError, "Location couldn't be set!");
1385                 }
1386                 else
1387                         PyErr_SetString(AUDError, device_not_3d_error);
1388         }
1389         catch(AUD_Exception& e)
1390         {
1391                 PyErr_SetString(AUDError, e.str);
1392         }
1393
1394         return -1;
1395 }
1396
1397 PyDoc_STRVAR(M_aud_Handle_velocity_doc,
1398                          "The source's velocity in 3D space, a 3D tuple of floats.");
1399
1400 static PyObject *
1401 Handle_get_velocity(Handle *self, void* nothing)
1402 {
1403         try
1404         {
1405                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1406                 if(handle)
1407                 {
1408                         AUD_Vector3 v = handle->getSourceVelocity();
1409                         return Py_BuildValue("(fff)", v.x(), v.y(), v.z());
1410                 }
1411                 else
1412                 {
1413                         PyErr_SetString(AUDError, device_not_3d_error);
1414                 }
1415         }
1416         catch(AUD_Exception& e)
1417         {
1418                 PyErr_SetString(AUDError, e.str);
1419         }
1420
1421         return NULL;
1422 }
1423
1424 static int
1425 Handle_set_velocity(Handle *self, PyObject *args, void* nothing)
1426 {
1427         float x, y, z;
1428
1429         if(!PyArg_Parse(args, "(fff):velocity", &x, &y, &z))
1430                 return -1;
1431
1432         try
1433         {
1434                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1435                 if(handle)
1436                 {
1437                         AUD_Vector3 velocity(x, y, z);
1438                         if(handle->setSourceVelocity(velocity))
1439                                 return 0;
1440                         PyErr_SetString(AUDError, "Couldn't set the velocity!");
1441                 }
1442                 else
1443                         PyErr_SetString(AUDError, device_not_3d_error);
1444         }
1445         catch(AUD_Exception& e)
1446         {
1447                 PyErr_SetString(AUDError, e.str);
1448         }
1449
1450         return -1;
1451 }
1452
1453 PyDoc_STRVAR(M_aud_Handle_orientation_doc,
1454                          "The source's orientation in 3D space as quaternion, a 4 float tuple.");
1455
1456 static PyObject *
1457 Handle_get_orientation(Handle *self, void* nothing)
1458 {
1459         try
1460         {
1461                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1462                 if(handle)
1463                 {
1464                         AUD_Quaternion o = handle->getSourceOrientation();
1465                         return Py_BuildValue("(ffff)", o.w(), o.x(), o.y(), o.z());
1466                 }
1467                 else
1468                 {
1469                         PyErr_SetString(AUDError, device_not_3d_error);
1470                 }
1471         }
1472         catch(AUD_Exception& e)
1473         {
1474                 PyErr_SetString(AUDError, e.str);
1475         }
1476
1477         return NULL;
1478 }
1479
1480 static int
1481 Handle_set_orientation(Handle *self, PyObject *args, void* nothing)
1482 {
1483         float w, x, y, z;
1484
1485         if(!PyArg_Parse(args, "(ffff):orientation", &w, &x, &y, &z))
1486                 return -1;
1487
1488         try
1489         {
1490                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1491                 if(handle)
1492                 {
1493                         AUD_Quaternion orientation(w, x, y, z);
1494                         if(handle->setSourceOrientation(orientation))
1495                                 return 0;
1496                         PyErr_SetString(AUDError, "Couldn't set the orientation!");
1497                 }
1498                 else
1499                         PyErr_SetString(AUDError, device_not_3d_error);
1500         }
1501         catch(AUD_Exception& e)
1502         {
1503                 PyErr_SetString(AUDError, e.str);
1504         }
1505
1506         return -1;
1507 }
1508
1509 PyDoc_STRVAR(M_aud_Handle_relative_doc,
1510                          "Whether the source's location, velocity and orientation is relative or absolute to the listener.");
1511
1512 static PyObject *
1513 Handle_get_relative(Handle *self, void* nothing)
1514 {
1515         try
1516         {
1517                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1518                 if(handle)
1519                 {
1520                         return PyBool_FromLong((long)handle->isRelative());
1521                 }
1522                 else
1523                 {
1524                         PyErr_SetString(AUDError, device_not_3d_error);
1525                 }
1526         }
1527         catch(AUD_Exception& e)
1528         {
1529                 PyErr_SetString(AUDError, e.str);
1530         }
1531
1532         return NULL;
1533 }
1534
1535 static int
1536 Handle_set_relative(Handle *self, PyObject *args, void* nothing)
1537 {
1538         if(!PyBool_Check(args))
1539         {
1540                 PyErr_SetString(PyExc_TypeError, "Value is not a boolean!");
1541                 return -1;
1542         }
1543
1544         bool relative = (args == Py_True);
1545
1546         try
1547         {
1548                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1549                 if(handle)
1550                 {
1551                         if(handle->setRelative(relative))
1552                                 return 0;
1553                         PyErr_SetString(AUDError, "Couldn't set the relativeness!");
1554                 }
1555                 else
1556                         PyErr_SetString(AUDError, device_not_3d_error);
1557         }
1558         catch(AUD_Exception& e)
1559         {
1560                 PyErr_SetString(AUDError, e.str);
1561         }
1562
1563         return -1;
1564 }
1565
1566 PyDoc_STRVAR(M_aud_Handle_volume_minimum_doc,
1567                          "The minimum volume of the source.\n\n"
1568                          ".. seealso:: :attr:`Device.distance_model`");
1569
1570 static PyObject *
1571 Handle_get_volume_minimum(Handle *self, void* nothing)
1572 {
1573         try
1574         {
1575                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1576                 if(handle)
1577                 {
1578                         return Py_BuildValue("f", handle->getVolumeMinimum());
1579                 }
1580                 else
1581                 {
1582                         PyErr_SetString(AUDError, device_not_3d_error);
1583                         return NULL;
1584                 }
1585         }
1586         catch(AUD_Exception& e)
1587         {
1588                 PyErr_SetString(AUDError, e.str);
1589                 return NULL;
1590         }
1591 }
1592
1593 static int
1594 Handle_set_volume_minimum(Handle *self, PyObject *args, void* nothing)
1595 {
1596         float volume;
1597
1598         if(!PyArg_Parse(args, "f:volume_minimum", &volume))
1599                 return -1;
1600
1601         try
1602         {
1603                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1604                 if(handle)
1605                 {
1606                         if(handle->setVolumeMinimum(volume))
1607                                 return 0;
1608                         PyErr_SetString(AUDError, "Couldn't set the minimum volume!");
1609                 }
1610                 else
1611                         PyErr_SetString(AUDError, device_not_3d_error);
1612         }
1613         catch(AUD_Exception& e)
1614         {
1615                 PyErr_SetString(AUDError, e.str);
1616         }
1617
1618         return -1;
1619 }
1620
1621 PyDoc_STRVAR(M_aud_Handle_volume_maximum_doc,
1622                          "The maximum volume of the source.\n\n"
1623                          ".. seealso:: :attr:`Device.distance_model`");
1624
1625 static PyObject *
1626 Handle_get_volume_maximum(Handle *self, void* nothing)
1627 {
1628         try
1629         {
1630                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1631                 if(handle)
1632                 {
1633                         return Py_BuildValue("f", handle->getVolumeMaximum());
1634                 }
1635                 else
1636                 {
1637                         PyErr_SetString(AUDError, device_not_3d_error);
1638                         return NULL;
1639                 }
1640         }
1641         catch(AUD_Exception& e)
1642         {
1643                 PyErr_SetString(AUDError, e.str);
1644                 return NULL;
1645         }
1646 }
1647
1648 static int
1649 Handle_set_volume_maximum(Handle *self, PyObject *args, void* nothing)
1650 {
1651         float volume;
1652
1653         if(!PyArg_Parse(args, "f:volume_maximum", &volume))
1654                 return -1;
1655
1656         try
1657         {
1658                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1659                 if(handle)
1660                 {
1661                         if(handle->setVolumeMaximum(volume))
1662                                 return 0;
1663                         PyErr_SetString(AUDError, "Couldn't set the maximum volume!");
1664                 }
1665                 else
1666                         PyErr_SetString(AUDError, device_not_3d_error);
1667         }
1668         catch(AUD_Exception& e)
1669         {
1670                 PyErr_SetString(AUDError, e.str);
1671         }
1672
1673         return -1;
1674 }
1675
1676 PyDoc_STRVAR(M_aud_Handle_distance_reference_doc,
1677                          "The reference distance of the source.\n"
1678                          "At this distance the volume will be exactly :attr:`volume`.\n\n"
1679                          ".. seealso:: :attr:`Device.distance_model`");
1680
1681 static PyObject *
1682 Handle_get_distance_reference(Handle *self, void* nothing)
1683 {
1684         try
1685         {
1686                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1687                 if(handle)
1688                 {
1689                         return Py_BuildValue("f", handle->getDistanceReference());
1690                 }
1691                 else
1692                 {
1693                         PyErr_SetString(AUDError, device_not_3d_error);
1694                         return NULL;
1695                 }
1696         }
1697         catch(AUD_Exception& e)
1698         {
1699                 PyErr_SetString(AUDError, e.str);
1700                 return NULL;
1701         }
1702 }
1703
1704 static int
1705 Handle_set_distance_reference(Handle *self, PyObject *args, void* nothing)
1706 {
1707         float distance;
1708
1709         if(!PyArg_Parse(args, "f:distance_reference", &distance))
1710                 return -1;
1711
1712         try
1713         {
1714                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1715                 if(handle)
1716                 {
1717                         if(handle->setDistanceReference(distance))
1718                                 return 0;
1719                         PyErr_SetString(AUDError, "Couldn't set the reference distance!");
1720                 }
1721                 else
1722                         PyErr_SetString(AUDError, device_not_3d_error);
1723         }
1724         catch(AUD_Exception& e)
1725         {
1726                 PyErr_SetString(AUDError, e.str);
1727         }
1728
1729         return -1;
1730 }
1731
1732 PyDoc_STRVAR(M_aud_Handle_distance_maximum_doc,
1733                          "The maximum distance of the source.\n"
1734                          "If the listener is further away the source volume will be 0.\n\n"
1735                          ".. seealso:: :attr:`Device.distance_model`");
1736
1737 static PyObject *
1738 Handle_get_distance_maximum(Handle *self, void* nothing)
1739 {
1740         try
1741         {
1742                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1743                 if(handle)
1744                 {
1745                         return Py_BuildValue("f", handle->getDistanceMaximum());
1746                 }
1747                 else
1748                 {
1749                         PyErr_SetString(AUDError, device_not_3d_error);
1750                         return NULL;
1751                 }
1752         }
1753         catch(AUD_Exception& e)
1754         {
1755                 PyErr_SetString(AUDError, e.str);
1756                 return NULL;
1757         }
1758 }
1759
1760 static int
1761 Handle_set_distance_maximum(Handle *self, PyObject *args, void* nothing)
1762 {
1763         float distance;
1764
1765         if(!PyArg_Parse(args, "f:distance_maximum", &distance))
1766                 return -1;
1767
1768         try
1769         {
1770                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1771                 if(handle)
1772                 {
1773                         if(handle->setDistanceMaximum(distance))
1774                                 return 0;
1775                         PyErr_SetString(AUDError, "Couldn't set the maximum distance!");
1776                 }
1777                 else
1778                         PyErr_SetString(AUDError, device_not_3d_error);
1779         }
1780         catch(AUD_Exception& e)
1781         {
1782                 PyErr_SetString(AUDError, e.str);
1783         }
1784
1785         return -1;
1786 }
1787
1788 PyDoc_STRVAR(M_aud_Handle_attenuation_doc,
1789                          "This factor is used for distance based attenuation of the "
1790                          "source.\n\n"
1791                          ".. seealso:: :attr:`Device.distance_model`");
1792
1793 static PyObject *
1794 Handle_get_attenuation(Handle *self, void* nothing)
1795 {
1796         try
1797         {
1798                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1799                 if(handle)
1800                 {
1801                         return Py_BuildValue("f", handle->getAttenuation());
1802                 }
1803                 else
1804                 {
1805                         PyErr_SetString(AUDError, device_not_3d_error);
1806                         return NULL;
1807                 }
1808         }
1809         catch(AUD_Exception& e)
1810         {
1811                 PyErr_SetString(AUDError, e.str);
1812                 return NULL;
1813         }
1814 }
1815
1816 static int
1817 Handle_set_attenuation(Handle *self, PyObject *args, void* nothing)
1818 {
1819         float factor;
1820
1821         if(!PyArg_Parse(args, "f:attenuation", &factor))
1822                 return -1;
1823
1824         try
1825         {
1826                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1827                 if(handle)
1828                 {
1829                         if(handle->setAttenuation(factor))
1830                                 return 0;
1831                         PyErr_SetString(AUDError, "Couldn't set the attenuation!");
1832                 }
1833                 else
1834                         PyErr_SetString(AUDError, device_not_3d_error);
1835         }
1836         catch(AUD_Exception& e)
1837         {
1838                 PyErr_SetString(AUDError, e.str);
1839         }
1840
1841         return -1;
1842 }
1843
1844 PyDoc_STRVAR(M_aud_Handle_cone_angle_inner_doc,
1845                          "The opening angle of the inner cone of the source. If the cone "
1846                          "values of a source are set there are two (audible) cones with "
1847                          "the apex at the :attr:`location` of the source and with infinite "
1848                          "height, heading in the direction of the source's "
1849                          ":attr:`orientation`.\n"
1850                          "In the inner cone the volume is normal. Outside the outer cone "
1851                          "the volume will be :attr:`cone_volume_outer` and in the area "
1852                          "between the volume will be interpolated linearly.");
1853
1854 static PyObject *
1855 Handle_get_cone_angle_inner(Handle *self, void* nothing)
1856 {
1857         try
1858         {
1859                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1860                 if(handle)
1861                 {
1862                         return Py_BuildValue("f", handle->getConeAngleInner());
1863                 }
1864                 else
1865                 {
1866                         PyErr_SetString(AUDError, device_not_3d_error);
1867                         return NULL;
1868                 }
1869         }
1870         catch(AUD_Exception& e)
1871         {
1872                 PyErr_SetString(AUDError, e.str);
1873                 return NULL;
1874         }
1875 }
1876
1877 static int
1878 Handle_set_cone_angle_inner(Handle *self, PyObject *args, void* nothing)
1879 {
1880         float angle;
1881
1882         if(!PyArg_Parse(args, "f:cone_angle_inner", &angle))
1883                 return -1;
1884
1885         try
1886         {
1887                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1888                 if(handle)
1889                 {
1890                         if(handle->setConeAngleInner(angle))
1891                                 return 0;
1892                         PyErr_SetString(AUDError, "Couldn't set the cone inner angle!");
1893                 }
1894                 else
1895                         PyErr_SetString(AUDError, device_not_3d_error);
1896         }
1897         catch(AUD_Exception& e)
1898         {
1899                 PyErr_SetString(AUDError, e.str);
1900         }
1901
1902         return -1;
1903 }
1904
1905 PyDoc_STRVAR(M_aud_Handle_cone_angle_outer_doc,
1906                          "The opening angle of the outer cone of the source.\n\n"
1907                          ".. seealso:: :attr:`cone_angle_inner`");
1908
1909 static PyObject *
1910 Handle_get_cone_angle_outer(Handle *self, void* nothing)
1911 {
1912         try
1913         {
1914                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1915                 if(handle)
1916                 {
1917                         return Py_BuildValue("f", handle->getConeAngleOuter());
1918                 }
1919                 else
1920                 {
1921                         PyErr_SetString(AUDError, device_not_3d_error);
1922                         return NULL;
1923                 }
1924         }
1925         catch(AUD_Exception& e)
1926         {
1927                 PyErr_SetString(AUDError, e.str);
1928                 return NULL;
1929         }
1930 }
1931
1932 static int
1933 Handle_set_cone_angle_outer(Handle *self, PyObject *args, void* nothing)
1934 {
1935         float angle;
1936
1937         if(!PyArg_Parse(args, "f:cone_angle_outer", &angle))
1938                 return -1;
1939
1940         try
1941         {
1942                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1943                 if(handle)
1944                 {
1945                         if(handle->setConeAngleOuter(angle))
1946                                 return 0;
1947                         PyErr_SetString(AUDError, "Couldn't set the cone outer angle!");
1948                 }
1949                 else
1950                         PyErr_SetString(AUDError, device_not_3d_error);
1951         }
1952         catch(AUD_Exception& e)
1953         {
1954                 PyErr_SetString(AUDError, e.str);
1955         }
1956
1957         return -1;
1958 }
1959
1960 PyDoc_STRVAR(M_aud_Handle_cone_volume_outer_doc,
1961                          "The volume outside the outer cone of the source.\n\n"
1962                          ".. seealso:: :attr:`cone_angle_inner`");
1963
1964 static PyObject *
1965 Handle_get_cone_volume_outer(Handle *self, void* nothing)
1966 {
1967         try
1968         {
1969                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1970                 if(handle)
1971                 {
1972                         return Py_BuildValue("f", handle->getConeVolumeOuter());
1973                 }
1974                 else
1975                 {
1976                         PyErr_SetString(AUDError, device_not_3d_error);
1977                         return NULL;
1978                 }
1979         }
1980         catch(AUD_Exception& e)
1981         {
1982                 PyErr_SetString(AUDError, e.str);
1983                 return NULL;
1984         }
1985 }
1986
1987 static int
1988 Handle_set_cone_volume_outer(Handle *self, PyObject *args, void* nothing)
1989 {
1990         float volume;
1991
1992         if(!PyArg_Parse(args, "f:cone_volume_outer", &volume))
1993                 return -1;
1994
1995         try
1996         {
1997                 AUD_I3DHandle* handle = dynamic_cast<AUD_I3DHandle*>(reinterpret_cast<boost::shared_ptr<AUD_IHandle>*>(self->handle)->get());
1998                 if(handle)
1999                 {
2000                         if(handle->setConeVolumeOuter(volume))
2001                                 return 0;
2002                         PyErr_SetString(AUDError, "Couldn't set the cone outer volume!");
2003                 }
2004                 else
2005                         PyErr_SetString(AUDError, device_not_3d_error);
2006         }
2007         catch(AUD_Exception& e)
2008         {
2009                 PyErr_SetString(AUDError, e.str);
2010         }
2011
2012         return -1;
2013 }
2014
2015 static PyGetSetDef Handle_properties[] = {
2016         {(char*)"position", (getter)Handle_get_position, (setter)Handle_set_position,
2017          M_aud_Handle_position_doc, NULL },
2018         {(char*)"keep", (getter)Handle_get_keep, (setter)Handle_set_keep,
2019          M_aud_Handle_keep_doc, NULL },
2020         {(char*)"status", (getter)Handle_get_status, NULL,
2021          M_aud_Handle_status_doc, NULL },
2022         {(char*)"volume", (getter)Handle_get_volume, (setter)Handle_set_volume,
2023          M_aud_Handle_volume_doc, NULL },
2024         {(char*)"pitch", (getter)Handle_get_pitch, (setter)Handle_set_pitch,
2025          M_aud_Handle_pitch_doc, NULL },
2026         {(char*)"loop_count", (getter)Handle_get_loop_count, (setter)Handle_set_loop_count,
2027          M_aud_Handle_loop_count_doc, NULL },
2028         {(char*)"location", (getter)Handle_get_location, (setter)Handle_set_location,
2029          M_aud_Handle_location_doc, NULL },
2030         {(char*)"velocity", (getter)Handle_get_velocity, (setter)Handle_set_velocity,
2031          M_aud_Handle_velocity_doc, NULL },
2032         {(char*)"orientation", (getter)Handle_get_orientation, (setter)Handle_set_orientation,
2033          M_aud_Handle_orientation_doc, NULL },
2034         {(char*)"relative", (getter)Handle_get_relative, (setter)Handle_set_relative,
2035          M_aud_Handle_relative_doc, NULL },
2036         {(char*)"volume_minimum", (getter)Handle_get_volume_minimum, (setter)Handle_set_volume_minimum,
2037          M_aud_Handle_volume_minimum_doc, NULL },
2038         {(char*)"volume_maximum", (getter)Handle_get_volume_maximum, (setter)Handle_set_volume_maximum,
2039          M_aud_Handle_volume_maximum_doc, NULL },
2040         {(char*)"distance_reference", (getter)Handle_get_distance_reference, (setter)Handle_set_distance_reference,
2041          M_aud_Handle_distance_reference_doc, NULL },
2042         {(char*)"distance_maximum", (getter)Handle_get_distance_maximum, (setter)Handle_set_distance_maximum,
2043          M_aud_Handle_distance_maximum_doc, NULL },
2044         {(char*)"attenuation", (getter)Handle_get_attenuation, (setter)Handle_set_attenuation,
2045          M_aud_Handle_attenuation_doc, NULL },
2046         {(char*)"cone_angle_inner", (getter)Handle_get_cone_angle_inner, (setter)Handle_set_cone_angle_inner,
2047          M_aud_Handle_cone_angle_inner_doc, NULL },
2048         {(char*)"cone_angle_outer", (getter)Handle_get_cone_angle_outer, (setter)Handle_set_cone_angle_outer,
2049          M_aud_Handle_cone_angle_outer_doc, NULL },
2050         {(char*)"cone_volume_outer", (getter)Handle_get_cone_volume_outer, (setter)Handle_set_cone_volume_outer,
2051          M_aud_Handle_cone_volume_outer_doc, NULL },
2052         {NULL}  /* Sentinel */
2053 };
2054
2055 PyDoc_STRVAR(M_aud_Handle_doc,
2056                          "Handle objects are playback handles that can be used to control "
2057                          "playback of a sound. If a sound is played back multiple times "
2058                          "then there are as many handles.");
2059
2060 static PyTypeObject HandleType = {
2061         PyVarObject_HEAD_INIT(NULL, 0)
2062         "aud.Handle",              /* tp_name */
2063         sizeof(Handle),            /* tp_basicsize */
2064         0,                         /* tp_itemsize */
2065         (destructor)Handle_dealloc,/* tp_dealloc */
2066         0,                         /* tp_print */
2067         0,                         /* tp_getattr */
2068         0,                         /* tp_setattr */
2069         0,                         /* tp_reserved */
2070         0,                         /* tp_repr */
2071         0,                         /* tp_as_number */
2072         0,                         /* tp_as_sequence */
2073         0,                         /* tp_as_mapping */
2074         0,                         /* tp_hash  */
2075         0,                         /* tp_call */
2076         0,                         /* tp_str */
2077         0,                         /* tp_getattro */
2078         0,                         /* tp_setattro */
2079         0,                         /* tp_as_buffer */
2080         Py_TPFLAGS_DEFAULT,        /* tp_flags */
2081         M_aud_Handle_doc,          /* tp_doc */
2082         0,                                 /* tp_traverse */
2083         0,                                 /* tp_clear */
2084         0,                                 /* tp_richcompare */
2085         0,                                 /* tp_weaklistoffset */
2086         0,                                 /* tp_iter */
2087         0,                                 /* tp_iternext */
2088         Handle_methods,            /* tp_methods */
2089         0,                         /* tp_members */
2090         Handle_properties,         /* tp_getset */
2091         0,                         /* tp_base */
2092         0,                         /* tp_dict */
2093         0,                         /* tp_descr_get */
2094         0,                         /* tp_descr_set */
2095         0,                         /* tp_dictoffset */
2096         0,                         /* tp_init */
2097         0,                         /* tp_alloc */
2098         0,                         /* tp_new */
2099 };
2100
2101 // ========== Device ==================================================
2102
2103 static void
2104 Device_dealloc(Device* self)
2105 {
2106         if(self->device)
2107                 delete reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device);
2108         Py_TYPE(self)->tp_free((PyObject *)self);
2109 }
2110
2111 static PyObject *
2112 Device_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2113 {
2114         Device *self;
2115
2116         static const char *kwlist[] = {"type", "rate", "channels", "format", "buffer_size", "name", NULL};
2117         int device;
2118         double rate = AUD_RATE_44100;
2119         int channels = AUD_CHANNELS_STEREO;
2120         int format = AUD_FORMAT_FLOAT32;
2121         int buffersize = AUD_DEFAULT_BUFFER_SIZE;
2122         const char* name = "Audaspace";
2123
2124         if(!PyArg_ParseTupleAndKeywords(args, kwds, "i|diiis:Device", const_cast<char**>(kwlist),
2125                                                                         &device, &rate, &channels, &format, &buffersize, &name))
2126                 return NULL;
2127
2128         if(buffersize < 128)
2129         {
2130                 PyErr_SetString(PyExc_ValueError, "buffer_size must be greater than 127!");
2131                 return NULL;
2132         }
2133
2134         self = (Device*)type->tp_alloc(type, 0);
2135         if(self != NULL)
2136         {
2137                 AUD_DeviceSpecs specs;
2138                 specs.channels = (AUD_Channels)channels;
2139                 specs.format = (AUD_SampleFormat)format;
2140                 specs.rate = (AUD_SampleRate)rate;
2141
2142                 self->device = NULL;
2143
2144                 try
2145                 {
2146                         switch(device)
2147                         {
2148                         case AUD_DEVICE_NULL:
2149                                 (void)specs; /* quiet warning when others disabled */
2150                                 self->device = new boost::shared_ptr<AUD_IDevice>(new AUD_NULLDevice());
2151                                 break;
2152                         case AUD_DEVICE_OPENAL:
2153 #ifdef WITH_OPENAL
2154                                 self->device = new boost::shared_ptr<AUD_IDevice>(new AUD_OpenALDevice(specs, buffersize));
2155 #endif
2156                                 break;
2157                         case AUD_DEVICE_SDL:
2158 #ifdef WITH_SDL
2159                                 self->device = new boost::shared_ptr<AUD_IDevice>(new AUD_SDLDevice(specs, buffersize));
2160 #endif
2161                                 break;
2162                         case AUD_DEVICE_JACK:
2163 #ifdef WITH_JACK
2164                                 self->device = new boost::shared_ptr<AUD_IDevice>(new AUD_JackDevice(name, specs, buffersize));
2165 #endif
2166                                 break;
2167                         case AUD_DEVICE_READ:
2168                                 break;
2169                         }
2170
2171                 }
2172                 catch(AUD_Exception& e)
2173                 {
2174                         Py_DECREF(self);
2175                         PyErr_SetString(AUDError, e.str);
2176                         return NULL;
2177                 }
2178
2179                 if(!self->device)
2180                 {
2181                         Py_DECREF(self);
2182                         PyErr_SetString(AUDError, "Unsupported device type!");
2183                         return NULL;
2184                 }
2185         }
2186
2187         return (PyObject *)self;
2188 }
2189
2190 PyDoc_STRVAR(M_aud_Device_play_doc,
2191                          "play(factory, keep=False)\n\n"
2192                          "Plays a factory.\n\n"
2193                          ":arg factory: The factory to play.\n"
2194                          ":type factory: :class:`Factory`\n"
2195                          ":arg keep: See :attr:`Handle.keep`.\n"
2196                          ":type keep: bool\n"
2197                          ":return: The playback handle with which playback can be "
2198                          "controlled with.\n"
2199                          ":rtype: :class:`Handle`");
2200
2201 static PyObject *
2202 Device_play(Device *self, PyObject *args, PyObject *kwds)
2203 {
2204         PyObject *object;
2205         PyObject *keepo = NULL;
2206
2207         bool keep = false;
2208
2209         static const char *kwlist[] = {"factory", "keep", NULL};
2210
2211         if(!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:play", const_cast<char**>(kwlist), &object, &keepo))
2212                 return NULL;
2213
2214         if(!PyObject_TypeCheck(object, &FactoryType))
2215         {
2216                 PyErr_SetString(PyExc_TypeError, "Object is not of type Factory!");
2217                 return NULL;
2218         }
2219
2220         if(keepo != NULL)
2221         {
2222                 if(!PyBool_Check(keepo))
2223                 {
2224                         PyErr_SetString(PyExc_TypeError, "keep is not a boolean!");
2225                         return NULL;
2226                 }
2227
2228                 keep = keepo == Py_True;
2229         }
2230
2231         Factory* sound = (Factory*)object;
2232         Handle *handle;
2233
2234         handle = (Handle*)HandleType.tp_alloc(&HandleType, 0);
2235         if(handle != NULL)
2236         {
2237                 try
2238                 {
2239                         handle->handle = new boost::shared_ptr<AUD_IHandle>((*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->play(*reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(sound->factory), keep));
2240                 }
2241                 catch(AUD_Exception& e)
2242                 {
2243                         Py_DECREF(handle);
2244                         PyErr_SetString(AUDError, e.str);
2245                         return NULL;
2246                 }
2247         }
2248
2249         return (PyObject *)handle;
2250 }
2251
2252 PyDoc_STRVAR(M_aud_Device_stopAll_doc,
2253                          "stopAll()\n\n"
2254                          "Stops all playing and paused sounds.");
2255
2256 static PyObject *
2257 Device_stopAll(Device *self)
2258 {
2259         try
2260         {
2261                 (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->stopAll();
2262                 Py_RETURN_NONE;
2263         }
2264         catch(AUD_Exception& e)
2265         {
2266                 PyErr_SetString(AUDError, e.str);
2267                 return NULL;
2268         }
2269 }
2270
2271 PyDoc_STRVAR(M_aud_Device_lock_doc,
2272                          "lock()\n\n"
2273                          "Locks the device so that it's guaranteed, that no samples are "
2274                          "read from the streams until :meth:`unlock` is called.\n"
2275                          "This is useful if you want to do start/stop/pause/resume some "
2276                          "sounds at the same time.\n\n"
2277                          ".. note:: The device has to be unlocked as often as locked to be "
2278                          "able to continue playback.\n\n"
2279                          ".. warning:: Make sure the time between locking and unlocking is "
2280                          "as short as possible to avoid clicks.");
2281
2282 static PyObject *
2283 Device_lock(Device *self)
2284 {
2285         try
2286         {
2287                 (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->lock();
2288                 Py_RETURN_NONE;
2289         }
2290         catch(AUD_Exception& e)
2291         {
2292                 PyErr_SetString(AUDError, e.str);
2293                 return NULL;
2294         }
2295 }
2296
2297 PyDoc_STRVAR(M_aud_Device_unlock_doc,
2298                          "unlock()\n\n"
2299                          "Unlocks the device after a lock call, see :meth:`lock` for "
2300                          "details.");
2301
2302 static PyObject *
2303 Device_unlock(Device *self)
2304 {
2305         try
2306         {
2307                 (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->unlock();
2308                 Py_RETURN_NONE;
2309         }
2310         catch(AUD_Exception& e)
2311         {
2312                 PyErr_SetString(AUDError, e.str);
2313                 return NULL;
2314         }
2315 }
2316
2317 static PyMethodDef Device_methods[] = {
2318         {"play", (PyCFunction)Device_play, METH_VARARGS | METH_KEYWORDS,
2319          M_aud_Device_play_doc
2320         },
2321         {"stopAll", (PyCFunction)Device_stopAll, METH_NOARGS,
2322          M_aud_Device_stopAll_doc
2323         },
2324         {"lock", (PyCFunction)Device_lock, METH_NOARGS,
2325          M_aud_Device_lock_doc
2326         },
2327         {"unlock", (PyCFunction)Device_unlock, METH_NOARGS,
2328          M_aud_Device_unlock_doc
2329         },
2330         {NULL}  /* Sentinel */
2331 };
2332
2333 PyDoc_STRVAR(M_aud_Device_rate_doc,
2334                          "The sampling rate of the device in Hz.");
2335
2336 static PyObject *
2337 Device_get_rate(Device *self, void* nothing)
2338 {
2339         try
2340         {
2341                 AUD_DeviceSpecs specs = (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->getSpecs();
2342                 return Py_BuildValue("d", specs.rate);
2343         }
2344         catch(AUD_Exception& e)
2345         {
2346                 PyErr_SetString(AUDError, e.str);
2347                 return NULL;
2348         }
2349 }
2350
2351 PyDoc_STRVAR(M_aud_Device_format_doc,
2352                          "The native sample format of the device.");
2353
2354 static PyObject *
2355 Device_get_format(Device *self, void* nothing)
2356 {
2357         try
2358         {
2359                 AUD_DeviceSpecs specs = (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->getSpecs();
2360                 return Py_BuildValue("i", specs.format);
2361         }
2362         catch(AUD_Exception& e)
2363         {
2364                 PyErr_SetString(AUDError, e.str);
2365                 return NULL;
2366         }
2367 }
2368
2369 PyDoc_STRVAR(M_aud_Device_channels_doc,
2370                          "The channel count of the device.");
2371
2372 static PyObject *
2373 Device_get_channels(Device *self, void* nothing)
2374 {
2375         try
2376         {
2377                 AUD_DeviceSpecs specs = (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->getSpecs();
2378                 return Py_BuildValue("i", specs.channels);
2379         }
2380         catch(AUD_Exception& e)
2381         {
2382                 PyErr_SetString(AUDError, e.str);
2383                 return NULL;
2384         }
2385 }
2386
2387 PyDoc_STRVAR(M_aud_Device_volume_doc,
2388                          "The overall volume of the device.");
2389
2390 static PyObject *
2391 Device_get_volume(Device *self, void* nothing)
2392 {
2393         try
2394         {
2395                 return Py_BuildValue("f", (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->getVolume());
2396         }
2397         catch(AUD_Exception& e)
2398         {
2399                 PyErr_SetString(AUDError, e.str);
2400                 return NULL;
2401         }
2402 }
2403
2404 static int
2405 Device_set_volume(Device *self, PyObject *args, void* nothing)
2406 {
2407         float volume;
2408
2409         if(!PyArg_Parse(args, "f:volume", &volume))
2410                 return -1;
2411
2412         try
2413         {
2414                 (*reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device))->setVolume(volume);
2415                 return 0;
2416         }
2417         catch(AUD_Exception& e)
2418         {
2419                 PyErr_SetString(AUDError, e.str);
2420                 return -1;
2421         }
2422 }
2423
2424 PyDoc_STRVAR(M_aud_Device_listener_location_doc,
2425                          "The listeners's location in 3D space, a 3D tuple of floats.");
2426
2427 static PyObject *
2428 Device_get_listener_location(Device *self, void* nothing)
2429 {
2430         try
2431         {
2432                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2433                 if(device)
2434                 {
2435                         AUD_Vector3 v = device->getListenerLocation();
2436                         return Py_BuildValue("(fff)", v.x(), v.y(), v.z());
2437                 }
2438                 else
2439                 {
2440                         PyErr_SetString(AUDError, device_not_3d_error);
2441                 }
2442         }
2443         catch(AUD_Exception& e)
2444         {
2445                 PyErr_SetString(AUDError, e.str);
2446         }
2447
2448         return NULL;
2449 }
2450
2451 static int
2452 Device_set_listener_location(Device *self, PyObject *args, void* nothing)
2453 {
2454         float x, y, z;
2455
2456         if(!PyArg_Parse(args, "(fff):listener_location", &x, &y, &z))
2457                 return -1;
2458
2459         try
2460         {
2461                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2462                 if(device)
2463                 {
2464                         AUD_Vector3 location(x, y, z);
2465                         device->setListenerLocation(location);
2466                         return 0;
2467                 }
2468                 else
2469                         PyErr_SetString(AUDError, device_not_3d_error);
2470         }
2471         catch(AUD_Exception& e)
2472         {
2473                 PyErr_SetString(AUDError, e.str);
2474         }
2475
2476         return -1;
2477 }
2478
2479 PyDoc_STRVAR(M_aud_Device_listener_velocity_doc,
2480                          "The listener's velocity in 3D space, a 3D tuple of floats.");
2481
2482 static PyObject *
2483 Device_get_listener_velocity(Device *self, void* nothing)
2484 {
2485         try
2486         {
2487                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2488                 if(device)
2489                 {
2490                         AUD_Vector3 v = device->getListenerVelocity();
2491                         return Py_BuildValue("(fff)", v.x(), v.y(), v.z());
2492                 }
2493                 else
2494                 {
2495                         PyErr_SetString(AUDError, device_not_3d_error);
2496                 }
2497         }
2498         catch(AUD_Exception& e)
2499         {
2500                 PyErr_SetString(AUDError, e.str);
2501         }
2502
2503         return NULL;
2504 }
2505
2506 static int
2507 Device_set_listener_velocity(Device *self, PyObject *args, void* nothing)
2508 {
2509         float x, y, z;
2510
2511         if(!PyArg_Parse(args, "(fff):listener_velocity", &x, &y, &z))
2512                 return -1;
2513
2514         try
2515         {
2516                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2517                 if(device)
2518                 {
2519                         AUD_Vector3 velocity(x, y, z);
2520                         device->setListenerVelocity(velocity);
2521                         return 0;
2522                 }
2523                 else
2524                         PyErr_SetString(AUDError, device_not_3d_error);
2525         }
2526         catch(AUD_Exception& e)
2527         {
2528                 PyErr_SetString(AUDError, e.str);
2529         }
2530
2531         return -1;
2532 }
2533
2534 PyDoc_STRVAR(M_aud_Device_listener_orientation_doc,
2535                          "The listener's orientation in 3D space as quaternion, a 4 float tuple.");
2536
2537 static PyObject *
2538 Device_get_listener_orientation(Device *self, void* nothing)
2539 {
2540         try
2541         {
2542                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2543                 if(device)
2544                 {
2545                         AUD_Quaternion o = device->getListenerOrientation();
2546                         return Py_BuildValue("(ffff)", o.w(), o.x(), o.y(), o.z());
2547                 }
2548                 else
2549                 {
2550                         PyErr_SetString(AUDError, device_not_3d_error);
2551                 }
2552         }
2553         catch(AUD_Exception& e)
2554         {
2555                 PyErr_SetString(AUDError, e.str);
2556         }
2557
2558         return NULL;
2559 }
2560
2561 static int
2562 Device_set_listener_orientation(Device *self, PyObject *args, void* nothing)
2563 {
2564         float w, x, y, z;
2565
2566         if(!PyArg_Parse(args, "(ffff):listener_orientation", &w, &x, &y, &z))
2567                 return -1;
2568
2569         try
2570         {
2571                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2572                 if(device)
2573                 {
2574                         AUD_Quaternion orientation(w, x, y, z);
2575                         device->setListenerOrientation(orientation);
2576                         return 0;
2577                 }
2578                 else
2579                         PyErr_SetString(AUDError, device_not_3d_error);
2580         }
2581         catch(AUD_Exception& e)
2582         {
2583                 PyErr_SetString(AUDError, e.str);
2584         }
2585
2586         return -1;
2587 }
2588
2589 PyDoc_STRVAR(M_aud_Device_speed_of_sound_doc,
2590                          "The speed of sound of the device.\n"
2591                          "The speed of sound in air is typically 343 m/s.");
2592
2593 static PyObject *
2594 Device_get_speed_of_sound(Device *self, void* nothing)
2595 {
2596         try
2597         {
2598                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2599                 if(device)
2600                 {
2601                         return Py_BuildValue("f", device->getSpeedOfSound());
2602                 }
2603                 else
2604                 {
2605                         PyErr_SetString(AUDError, device_not_3d_error);
2606                         return NULL;
2607                 }
2608         }
2609         catch(AUD_Exception& e)
2610         {
2611                 PyErr_SetString(AUDError, e.str);
2612                 return NULL;
2613         }
2614 }
2615
2616 static int
2617 Device_set_speed_of_sound(Device *self, PyObject *args, void* nothing)
2618 {
2619         float speed;
2620
2621         if(!PyArg_Parse(args, "f:speed_of_sound", &speed))
2622                 return -1;
2623
2624         try
2625         {
2626                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2627                 if(device)
2628                 {
2629                         device->setSpeedOfSound(speed);
2630                         return 0;
2631                 }
2632                 else
2633                         PyErr_SetString(AUDError, device_not_3d_error);
2634         }
2635         catch(AUD_Exception& e)
2636         {
2637                 PyErr_SetString(AUDError, e.str);
2638         }
2639
2640         return -1;
2641 }
2642
2643 PyDoc_STRVAR(M_aud_Device_doppler_factor_doc,
2644                          "The doppler factor of the device.\n"
2645                          "This factor is a scaling factor for the velocity vectors in "
2646                          "doppler calculation. So a value bigger than 1 will exaggerate "
2647                          "the effect as it raises the velocity.");
2648
2649 static PyObject *
2650 Device_get_doppler_factor(Device *self, void* nothing)
2651 {
2652         try
2653         {
2654                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2655                 if(device)
2656                 {
2657                         return Py_BuildValue("f", device->getDopplerFactor());
2658                 }
2659                 else
2660                 {
2661                         PyErr_SetString(AUDError, device_not_3d_error);
2662                         return NULL;
2663                 }
2664         }
2665         catch(AUD_Exception& e)
2666         {
2667                 PyErr_SetString(AUDError, e.str);
2668                 return NULL;
2669         }
2670 }
2671
2672 static int
2673 Device_set_doppler_factor(Device *self, PyObject *args, void* nothing)
2674 {
2675         float factor;
2676
2677         if(!PyArg_Parse(args, "f:doppler_factor", &factor))
2678                 return -1;
2679
2680         try
2681         {
2682                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2683                 if(device)
2684                 {
2685                         device->setDopplerFactor(factor);
2686                         return 0;
2687                 }
2688                 else
2689                         PyErr_SetString(AUDError, device_not_3d_error);
2690         }
2691         catch(AUD_Exception& e)
2692         {
2693                 PyErr_SetString(AUDError, e.str);
2694         }
2695
2696         return -1;
2697 }
2698
2699 PyDoc_STRVAR(M_aud_Device_distance_model_doc,
2700                          "The distance model of the device.\n\n"
2701                          ".. seealso:: http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm#_Toc199835864");
2702
2703 static PyObject *
2704 Device_get_distance_model(Device *self, void* nothing)
2705 {
2706         try
2707         {
2708                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2709                 if(device)
2710                 {
2711                         return Py_BuildValue("i", int(device->getDistanceModel()));
2712                 }
2713                 else
2714                 {
2715                         PyErr_SetString(AUDError, device_not_3d_error);
2716                         return NULL;
2717                 }
2718         }
2719         catch(AUD_Exception& e)
2720         {
2721                 PyErr_SetString(AUDError, e.str);
2722                 return NULL;
2723         }
2724 }
2725
2726 static int
2727 Device_set_distance_model(Device *self, PyObject *args, void* nothing)
2728 {
2729         int model;
2730
2731         if(!PyArg_Parse(args, "i:distance_model", &model))
2732                 return -1;
2733
2734         try
2735         {
2736                 AUD_I3DDevice* device = dynamic_cast<AUD_I3DDevice*>(reinterpret_cast<boost::shared_ptr<AUD_IDevice>*>(self->device)->get());
2737                 if(device)
2738                 {
2739                         device->setDistanceModel(AUD_DistanceModel(model));
2740                         return 0;
2741                 }
2742                 else
2743                         PyErr_SetString(AUDError, device_not_3d_error);
2744         }
2745         catch(AUD_Exception& e)
2746         {
2747                 PyErr_SetString(AUDError, e.str);
2748         }
2749
2750         return -1;
2751 }
2752
2753 static PyGetSetDef Device_properties[] = {
2754         {(char*)"rate", (getter)Device_get_rate, NULL,
2755          M_aud_Device_rate_doc, NULL },
2756         {(char*)"format", (getter)Device_get_format, NULL,
2757          M_aud_Device_format_doc, NULL },
2758         {(char*)"channels", (getter)Device_get_channels, NULL,
2759          M_aud_Device_channels_doc, NULL },
2760         {(char*)"volume", (getter)Device_get_volume, (setter)Device_set_volume,
2761          M_aud_Device_volume_doc, NULL },
2762         {(char*)"listener_location", (getter)Device_get_listener_location, (setter)Device_set_listener_location,
2763          M_aud_Device_listener_location_doc, NULL },
2764         {(char*)"listener_velocity", (getter)Device_get_listener_velocity, (setter)Device_set_listener_velocity,
2765          M_aud_Device_listener_velocity_doc, NULL },
2766         {(char*)"listener_orientation", (getter)Device_get_listener_orientation, (setter)Device_set_listener_orientation,
2767          M_aud_Device_listener_orientation_doc, NULL },
2768         {(char*)"speed_of_sound", (getter)Device_get_speed_of_sound, (setter)Device_set_speed_of_sound,
2769          M_aud_Device_speed_of_sound_doc, NULL },
2770         {(char*)"doppler_factor", (getter)Device_get_doppler_factor, (setter)Device_set_doppler_factor,
2771          M_aud_Device_doppler_factor_doc, NULL },
2772         {(char*)"distance_model", (getter)Device_get_distance_model, (setter)Device_set_distance_model,
2773          M_aud_Device_distance_model_doc, NULL },
2774         {NULL}  /* Sentinel */
2775 };
2776
2777 PyDoc_STRVAR(M_aud_Device_doc,
2778                          "Device objects represent an audio output backend like OpenAL or "
2779                          "SDL, but might also represent a file output or RAM buffer "
2780                          "output.");
2781
2782 static PyTypeObject DeviceType = {
2783         PyVarObject_HEAD_INIT(NULL, 0)
2784         "aud.Device",              /* tp_name */
2785         sizeof(Device),            /* tp_basicsize */
2786         0,                         /* tp_itemsize */
2787         (destructor)Device_dealloc,/* tp_dealloc */
2788         0,                         /* tp_print */
2789         0,                         /* tp_getattr */
2790         0,                         /* tp_setattr */
2791         0,                         /* tp_reserved */
2792         0,                         /* tp_repr */
2793         0,                         /* tp_as_number */
2794         0,                         /* tp_as_sequence */
2795         0,                         /* tp_as_mapping */
2796         0,                         /* tp_hash  */
2797         0,                         /* tp_call */
2798         0,                         /* tp_str */
2799         0,                         /* tp_getattro */
2800         0,                         /* tp_setattro */
2801         0,                         /* tp_as_buffer */
2802         Py_TPFLAGS_DEFAULT,        /* tp_flags */
2803         M_aud_Device_doc,          /* tp_doc */
2804         0,                                 /* tp_traverse */
2805         0,                                 /* tp_clear */
2806         0,                                 /* tp_richcompare */
2807         0,                                 /* tp_weaklistoffset */
2808         0,                                 /* tp_iter */
2809         0,                                 /* tp_iternext */
2810         Device_methods,            /* tp_methods */
2811         0,                         /* tp_members */
2812         Device_properties,         /* tp_getset */
2813         0,                         /* tp_base */
2814         0,                         /* tp_dict */
2815         0,                         /* tp_descr_get */
2816         0,                         /* tp_descr_set */
2817         0,                         /* tp_dictoffset */
2818         0,                         /* tp_init */
2819         0,                         /* tp_alloc */
2820         Device_new,                /* tp_new */
2821 };
2822
2823 PyObject *
2824 Device_empty()
2825 {
2826         return DeviceType.tp_alloc(&DeviceType, 0);
2827 }
2828
2829 PyObject *
2830 Factory_empty()
2831 {
2832         return FactoryType.tp_alloc(&FactoryType, 0);
2833 }
2834
2835 Factory*
2836 checkFactory(PyObject *factory)
2837 {
2838         if(!PyObject_TypeCheck(factory, &FactoryType))
2839         {
2840                 PyErr_SetString(PyExc_TypeError, "Object is not of type Factory!");
2841                 return NULL;
2842         }
2843
2844         return (Factory*)factory;
2845 }
2846
2847
2848 // ====================================================================
2849
2850 PyDoc_STRVAR(M_aud_doc,
2851                          "This module provides access to the audaspace audio library.");
2852
2853 static struct PyModuleDef audmodule = {
2854         PyModuleDef_HEAD_INIT,
2855         "aud",     /* name of module */
2856         M_aud_doc, /* module documentation */
2857         -1,        /* size of per-interpreter state of the module,
2858                                   or -1 if the module keeps state in global variables. */
2859    NULL, NULL, NULL, NULL, NULL
2860 };
2861
2862 PyMODINIT_FUNC
2863 PyInit_aud(void)
2864 {
2865         PyObject *m;
2866
2867         if(PyType_Ready(&FactoryType) < 0)
2868                 return NULL;
2869
2870         if(PyType_Ready(&DeviceType) < 0)
2871                 return NULL;
2872
2873         if(PyType_Ready(&HandleType) < 0)
2874                 return NULL;
2875
2876         m = PyModule_Create(&audmodule);
2877         if(m == NULL)
2878                 return NULL;
2879
2880         Py_INCREF(&FactoryType);
2881         PyModule_AddObject(m, "Factory", (PyObject *)&FactoryType);
2882
2883         Py_INCREF(&DeviceType);
2884         PyModule_AddObject(m, "Device", (PyObject *)&DeviceType);
2885
2886         Py_INCREF(&HandleType);
2887         PyModule_AddObject(m, "Handle", (PyObject *)&HandleType);
2888
2889         AUDError = PyErr_NewException("aud.error", NULL, NULL);
2890         Py_INCREF(AUDError);
2891         PyModule_AddObject(m, "error", AUDError);
2892
2893         // device constants
2894         PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_NULL);
2895         PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_OPENAL);
2896         PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_SDL);
2897         PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_JACK);
2898         //PY_MODULE_ADD_CONSTANT(m, AUD_DEVICE_READ);
2899         // format constants
2900         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_FLOAT32);
2901         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_FLOAT64);
2902         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_INVALID);
2903         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_S16);
2904         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_S24);
2905         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_S32);
2906         PY_MODULE_ADD_CONSTANT(m, AUD_FORMAT_U8);
2907         // status constants
2908         PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_INVALID);
2909         PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_PAUSED);
2910         PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_PLAYING);
2911         // distance model constants
2912         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_EXPONENT);
2913         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_EXPONENT_CLAMPED);
2914         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_INVERSE);
2915         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_INVERSE_CLAMPED);
2916         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_LINEAR);
2917         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_LINEAR_CLAMPED);
2918         PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_INVALID);
2919
2920         return m;
2921 }