Py BGE API
[blender.git] / source / gameengine / Ketsji / KX_SoundActuator.cpp
1 /**
2  * KX_SoundActuator.cpp
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program 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 this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  *
31  */
32
33 #include "KX_SoundActuator.h"
34 #include "SND_SoundObject.h"
35 #include "KX_GameObject.h"
36 #include "SND_SoundObject.h"
37 #include "SND_Scene.h" // needed for replication
38 #include <iostream>
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 /* ------------------------------------------------------------------------- */
45 /* Native functions                                                          */
46 /* ------------------------------------------------------------------------- */
47 KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
48                                                                    SND_SoundObject* sndobj,
49                                                                    SND_Scene*   sndscene,
50                                                                    KX_SOUNDACT_TYPE type,
51                                                                    short start,
52                                                                    short end,
53                                                                    PyTypeObject* T)
54                                                                    : SCA_IActuator(gameobj,T)
55 {
56         m_soundObject = sndobj;
57         m_soundScene = sndscene;
58         m_type = type;
59         m_lastEvent = true;
60         m_isplaying = false;
61         m_startFrame = start;
62         m_endFrame = end;
63         m_pino = false;
64         
65
66 }
67
68
69
70 KX_SoundActuator::~KX_SoundActuator()
71 {
72         if (m_soundObject)
73         {
74                 m_soundScene->RemoveActiveObject(m_soundObject);
75                 m_soundScene->DeleteObject(m_soundObject);
76         }
77 }
78
79
80
81 CValue* KX_SoundActuator::GetReplica()
82 {
83         KX_SoundActuator* replica = new KX_SoundActuator(*this);
84         replica->ProcessReplica();
85         if (m_soundObject)
86         {
87             SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject);
88                 replica->setSoundObject(soundobj);
89                 m_soundScene->AddObject(soundobj);
90         }
91         
92         // this will copy properties and so on...
93         CValue::AddDataToReplica(replica);
94         return replica;
95 };
96
97
98
99 bool KX_SoundActuator::Update(double curtime, bool frame)
100 {
101         if (!frame)
102                 return true;
103         bool result = false;
104
105         // do nothing on negative events, otherwise sounds are played twice!
106         bool bNegativeEvent = IsNegativeEvent();
107
108         RemoveAllEvents();
109
110         if (!m_soundObject)
111                 return false;
112
113         // actual audio device playing state
114         bool isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false;
115
116         if (m_pino)
117         {
118                 bNegativeEvent = true;
119                 m_pino = false;
120         }
121
122         if (bNegativeEvent)
123         {       
124                 // here must be a check if it is still playing
125                 if (m_isplaying && isplaying) 
126                 {
127                         switch (m_type)
128                         {
129                         case KX_SOUNDACT_PLAYSTOP:
130                         case KX_SOUNDACT_LOOPSTOP:
131                         case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
132                                 {
133                                         m_soundScene->RemoveActiveObject(m_soundObject);
134                                         break;
135                                 }
136                         case KX_SOUNDACT_PLAYEND:
137                                 {
138                                         m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED);
139                                         break;
140                                 }
141                         case KX_SOUNDACT_LOOPEND:
142                         case KX_SOUNDACT_LOOPBIDIRECTIONAL:
143                                 {
144                                         m_soundObject->SetLoopMode(SND_LOOP_OFF);
145                                         m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED);
146                                         break;
147                                 }
148                         default:
149                                 // implement me !!
150                                 break;
151                         }
152                 }
153                 // remember that we tried to stop the actuator
154                 m_isplaying = false;
155         }
156         else
157         {
158                 if (!m_isplaying)
159                 {
160                         switch (m_type)
161                         {
162                         case KX_SOUNDACT_LOOPBIDIRECTIONAL:
163                         case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
164                                 {
165                                         m_soundObject->SetLoopMode(SND_LOOP_BIDIRECTIONAL);
166                                         m_soundScene->AddActiveObject(m_soundObject, curtime);
167                                         m_isplaying = true;
168                                         result = true;
169                                         break;
170                                 }
171                         case KX_SOUNDACT_LOOPEND:
172                         case KX_SOUNDACT_LOOPSTOP:
173                                 {
174                                         m_soundObject->SetLoopMode(SND_LOOP_NORMAL);
175                                         m_soundScene->AddActiveObject(m_soundObject, curtime);
176                                         m_isplaying = true;
177                                         result = true;
178                                         break;
179                                 }
180                         case KX_SOUNDACT_PLAYSTOP:
181                         case KX_SOUNDACT_PLAYEND:
182                                 {
183                                         m_soundObject->SetLoopMode(SND_LOOP_OFF);
184                                         m_soundScene->AddActiveObject(m_soundObject, curtime);
185                                         m_isplaying = true;
186                                         result = true;
187                                         break;
188                                 }
189                         default:
190                                 // implement me !!
191                                 break;
192                         }
193                 }
194         }
195         // verify that the sound is still playing
196         isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false;
197
198         if (isplaying)
199         {
200                 m_soundObject->SetPosition(((KX_GameObject*)this->GetParent())->NodeGetWorldPosition());
201                 m_soundObject->SetVelocity(((KX_GameObject*)this->GetParent())->GetLinearVelocity());
202                 m_soundObject->SetOrientation(((KX_GameObject*)this->GetParent())->NodeGetWorldOrientation());
203                 result = true;
204         }
205         else
206         {
207                 m_isplaying = false;
208                 result = false;
209         }
210         /*
211         if (result && (m_soundObject->IsLifeSpanOver(curtime)) && ((m_type == KX_SOUNDACT_PLAYEND) || (m_type == KX_SOUNDACT_PLAYSTOP)))
212         {
213                 m_pino = true;
214         }
215         */
216         return result;
217 }
218
219
220
221 void KX_SoundActuator::setSoundObject(class SND_SoundObject* soundobject)
222 {
223         m_soundObject = soundobject;
224 }
225
226
227
228 /* ------------------------------------------------------------------------- */
229 /* Python functions                                                          */
230 /* ------------------------------------------------------------------------- */
231
232
233
234 /* Integration hooks ------------------------------------------------------- */
235 PyTypeObject KX_SoundActuator::Type = {
236         PyObject_HEAD_INIT(&PyType_Type)
237                 0,
238                 "KX_SoundActuator",
239                 sizeof(KX_SoundActuator),
240                 0,
241                 PyDestructor,
242                 0,
243                 __getattr,
244                 __setattr,
245                 0, //&MyPyCompare,
246                 __repr,
247                 0, //&cvalue_as_number,
248                 0,
249                 0,
250                 0,
251                 0
252 };
253
254
255
256 PyParentObject KX_SoundActuator::Parents[] = {
257         &KX_SoundActuator::Type,
258                 &SCA_IActuator::Type,
259                 &SCA_ILogicBrick::Type,
260                 &CValue::Type,
261                 NULL
262 };
263
264
265
266 PyMethodDef KX_SoundActuator::Methods[] = {
267         {"setFilename", (PyCFunction) KX_SoundActuator::sPySetFilename, METH_VARARGS,NULL},
268         {"getFilename", (PyCFunction) KX_SoundActuator::sPyGetFilename, METH_VARARGS,NULL},
269         {"startSound",(PyCFunction) KX_SoundActuator::sPyStartSound,METH_VARARGS,NULL},
270         {"pauseSound",(PyCFunction) KX_SoundActuator::sPyPauseSound,METH_VARARGS,NULL},
271         {"stopSound",(PyCFunction) KX_SoundActuator::sPyStopSound,METH_VARARGS,NULL},
272         {"setGain",(PyCFunction) KX_SoundActuator::sPySetGain,METH_VARARGS,NULL},
273         {"getGain",(PyCFunction) KX_SoundActuator::sPyGetGain,METH_VARARGS,NULL},
274         {"setPitch",(PyCFunction) KX_SoundActuator::sPySetPitch,METH_VARARGS,NULL},
275         {"getPitch",(PyCFunction) KX_SoundActuator::sPyGetPitch,METH_VARARGS,NULL},
276         {"setRollOffFactor",(PyCFunction) KX_SoundActuator::sPySetRollOffFactor,METH_VARARGS,NULL},
277         {"getRollOffFactor",(PyCFunction) KX_SoundActuator::sPyGetRollOffFactor,METH_VARARGS,NULL},
278         {"setLooping",(PyCFunction) KX_SoundActuator::sPySetLooping,METH_VARARGS,NULL},
279         {"getLooping",(PyCFunction) KX_SoundActuator::sPyGetLooping,METH_VARARGS,NULL},
280         {"setPosition",(PyCFunction) KX_SoundActuator::sPySetPosition,METH_VARARGS,NULL},
281         {"setVelocity",(PyCFunction) KX_SoundActuator::sPySetVelocity,METH_VARARGS,NULL},
282         {"setOrientation",(PyCFunction) KX_SoundActuator::sPySetOrientation,METH_VARARGS,NULL},
283         {"setType",(PyCFunction) KX_SoundActuator::sPySetType,METH_VARARGS,NULL},
284         {"getType",(PyCFunction) KX_SoundActuator::sPyGetType,METH_VARARGS,NULL},
285         {NULL,NULL,NULL,NULL} //Sentinel
286 };
287
288 PyAttributeDef KX_SoundActuator::Attributes[] = {
289         { NULL }        //Sentinel
290 };
291
292 PyObject* KX_SoundActuator::_getattr(const char *attr)
293 {
294         _getattr_up(SCA_IActuator);
295 }
296
297
298
299 PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObject* kwds)
300 {
301         char *soundName = NULL;
302         // void *soundPointer = NULL; /*unused*/
303         
304         if (!PyArg_ParseTuple(args, "s", &soundName))
305                 return NULL;
306
307         Py_RETURN_NONE;
308 }
309
310
311
312 PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds)
313 {
314         if (!m_soundObject)
315         {
316                 return PyString_FromString("");
317         }
318         STR_String objectname = m_soundObject->GetObjectName();
319         char* name = objectname.Ptr();
320         
321         if (!name) {
322                 PyErr_SetString(PyExc_RuntimeError, "Unable to get sound filename");
323                 return NULL;
324         } else
325                 return PyString_FromString(name);
326 }
327
328
329
330 PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds)
331 {
332         if (m_soundObject)
333                 // This has no effect if the actuator is not active.
334                 // To start the sound you must activate the actuator. 
335                 // This function is to restart the sound.
336                 m_soundObject->StartSound();    
337         Py_RETURN_NONE;
338 }         
339
340
341
342 PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds)
343 {
344         if (m_soundObject)
345                 // unfortunately, openal does not implement pause correctly, it is equivalent to a stop
346                 m_soundObject->PauseSound();    
347         Py_RETURN_NONE;
348
349
350
351
352 PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds)
353 {
354         if (m_soundObject)
355                 m_soundObject->StopSound();     
356         Py_RETURN_NONE;
357 }
358
359
360
361 PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* kwds)
362 {
363         float gain = 1.0;
364         if (!PyArg_ParseTuple(args, "f", &gain))
365                 return NULL;
366         
367         if (m_soundObject)
368                 m_soundObject->SetGain(gain);
369         
370         Py_RETURN_NONE;
371 }         
372
373
374
375 PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds)
376 {
377         float gain = (m_soundObject) ? m_soundObject->GetGain() : 1.0f;
378         PyObject* result = PyFloat_FromDouble(gain);
379         
380         return result;
381 }
382
383
384
385 PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* kwds)
386 {
387         float pitch = 1.0;
388         if (!PyArg_ParseTuple(args, "f", &pitch))
389                 return NULL;
390         
391         if (m_soundObject)
392                 m_soundObject->SetPitch(pitch);
393         
394         Py_RETURN_NONE;
395 }         
396
397
398
399 PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds)
400 {
401         float pitch = (m_soundObject) ? m_soundObject->GetPitch() : 1.0;
402         PyObject* result = PyFloat_FromDouble(pitch);
403         
404         return result;
405 }
406
407
408
409 PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
410 {
411         float rollofffactor = 1.0;
412         if (!PyArg_ParseTuple(args, "f", &rollofffactor))
413                 return NULL;
414         
415         if (m_soundObject)
416                 m_soundObject->SetRollOffFactor(rollofffactor);
417
418         Py_RETURN_NONE;
419 }         
420
421
422
423 PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
424 {
425         float rollofffactor = (m_soundObject) ? m_soundObject->GetRollOffFactor() : 1.0;
426         PyObject* result = PyFloat_FromDouble(rollofffactor);
427         
428         return result;
429 }
430
431
432
433 PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObject* kwds)
434 {
435         bool looping = 1;
436         if (!PyArg_ParseTuple(args, "i", &looping))
437                 return NULL;
438         
439         if (m_soundObject)
440                 m_soundObject->SetLoopMode(looping);
441         
442         Py_RETURN_NONE;
443 }         
444
445
446
447 PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds)
448 {
449         int looping = (m_soundObject) ? m_soundObject->GetLoopMode() : (int)SND_LOOP_OFF;
450         PyObject* result = PyInt_FromLong(looping);
451         
452         return result;
453 }
454
455
456
457 PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObject* kwds)
458 {
459         MT_Point3 pos;
460         pos[0] = 0.0;
461         pos[1] = 0.0;
462         pos[2] = 0.0;
463
464         if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2]))
465                 return NULL;
466         
467         if (m_soundObject)
468                 m_soundObject->SetPosition(pos);
469         
470         Py_RETURN_NONE;
471 }         
472
473
474
475 PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObject* kwds)
476 {
477         MT_Vector3 vel;
478         vel[0] = 0.0;
479         vel[1] = 0.0;
480         vel[2] = 0.0;
481
482         if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2]))
483                 return NULL;
484         
485         if (m_soundObject)
486                 m_soundObject->SetVelocity(vel);
487         
488         Py_RETURN_NONE;
489 }         
490
491
492
493 PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyObject* kwds)
494 {
495         MT_Matrix3x3 ori;
496         ori[0][0] = 1.0;
497         ori[0][1] = 0.0;
498         ori[0][2] = 0.0;
499         ori[1][0] = 0.0;
500         ori[1][1] = 1.0;
501         ori[1][2] = 0.0;
502         ori[2][0] = 0.0;
503         ori[2][1] = 0.0;
504         ori[2][2] = 1.0;
505
506         if (!PyArg_ParseTuple(args, "fffffffff", &ori[0][0], &ori[0][1], &ori[0][2], &ori[1][0], &ori[1][1], &ori[1][2], &ori[2][0], &ori[2][1], &ori[2][2]))
507                 return NULL;
508         
509         if (m_soundObject)
510                 m_soundObject->SetOrientation(ori);
511         
512         Py_RETURN_NONE;
513 }
514
515 PyObject* KX_SoundActuator::PySetType(PyObject* self, PyObject* args, PyObject* kwds)
516 {
517         int typeArg;
518
519         if (!PyArg_ParseTuple(args, "i", &typeArg)) {
520                 return NULL;
521         }
522
523         if ( (typeArg > KX_SOUNDACT_NODEF)
524           && (typeArg < KX_SOUNDACT_MAX) ) {
525                 m_type = (KX_SOUNDACT_TYPE) typeArg;
526         }
527
528         Py_RETURN_NONE;
529 }
530
531 PyObject* KX_SoundActuator::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
532 {
533         return PyInt_FromLong(m_type);
534 }
535
536
537