Merge 16964:17122
[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
289
290 PyObject* KX_SoundActuator::_getattr(const STR_String& attr)
291 {
292         _getattr_up(SCA_IActuator);
293 }
294
295
296
297 PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObject* kwds)
298 {
299         char *soundName = NULL;
300         // void *soundPointer = NULL; /*unused*/
301         
302         if (!PyArg_ParseTuple(args, "s", &soundName))
303                 return NULL;
304
305         Py_Return;
306 }
307
308
309
310 PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds)
311 {
312         if (!m_soundObject)
313         {
314                 return PyString_FromString("");
315         }
316         STR_String objectname = m_soundObject->GetObjectName();
317         char* name = objectname.Ptr();
318         
319         if (!name) {
320                 PyErr_SetString(PyExc_RuntimeError, "Unable to get sound filename");
321                 return NULL;
322         } else
323                 return PyString_FromString(name);
324 }
325
326
327
328 PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds)
329 {
330         if (m_soundObject)
331                 // This has no effect if the actuator is not active.
332                 // To start the sound you must activate the actuator. 
333                 // This function is to restart the sound.
334                 m_soundObject->StartSound();    
335         Py_Return;
336 }         
337
338
339
340 PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds)
341 {
342         if (m_soundObject)
343                 // unfortunately, openal does not implement pause correctly, it is equivalent to a stop
344                 m_soundObject->PauseSound();    
345         Py_Return;
346
347
348
349
350 PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds)
351 {
352         if (m_soundObject)
353                 m_soundObject->StopSound();     
354         Py_Return;
355 }
356
357
358
359 PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* kwds)
360 {
361         float gain = 1.0;
362         if (!PyArg_ParseTuple(args, "f", &gain))
363                 return NULL;
364         
365         if (m_soundObject)
366                 m_soundObject->SetGain(gain);
367         
368         Py_Return;
369 }         
370
371
372
373 PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds)
374 {
375         float gain = (m_soundObject) ? m_soundObject->GetGain() : 1.0f;
376         PyObject* result = PyFloat_FromDouble(gain);
377         
378         return result;
379 }
380
381
382
383 PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* kwds)
384 {
385         float pitch = 1.0;
386         if (!PyArg_ParseTuple(args, "f", &pitch))
387                 return NULL;
388         
389         if (m_soundObject)
390                 m_soundObject->SetPitch(pitch);
391         
392         Py_Return;
393 }         
394
395
396
397 PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds)
398 {
399         float pitch = (m_soundObject) ? m_soundObject->GetPitch() : 1.0;
400         PyObject* result = PyFloat_FromDouble(pitch);
401         
402         return result;
403 }
404
405
406
407 PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
408 {
409         float rollofffactor = 1.0;
410         if (!PyArg_ParseTuple(args, "f", &rollofffactor))
411                 return NULL;
412         
413         if (m_soundObject)
414                 m_soundObject->SetRollOffFactor(rollofffactor);
415
416         Py_Return;
417 }         
418
419
420
421 PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
422 {
423         float rollofffactor = (m_soundObject) ? m_soundObject->GetRollOffFactor() : 1.0;
424         PyObject* result = PyFloat_FromDouble(rollofffactor);
425         
426         return result;
427 }
428
429
430
431 PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObject* kwds)
432 {
433         bool looping = 1;
434         if (!PyArg_ParseTuple(args, "i", &looping))
435                 return NULL;
436         
437         if (m_soundObject)
438                 m_soundObject->SetLoopMode(looping);
439         
440         Py_Return;
441 }         
442
443
444
445 PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds)
446 {
447         int looping = (m_soundObject) ? m_soundObject->GetLoopMode() : SND_LOOP_OFF;
448         PyObject* result = PyInt_FromLong(looping);
449         
450         return result;
451 }
452
453
454
455 PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObject* kwds)
456 {
457         MT_Point3 pos;
458         pos[0] = 0.0;
459         pos[1] = 0.0;
460         pos[2] = 0.0;
461
462         if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2]))
463                 return NULL;
464         
465         if (m_soundObject)
466                 m_soundObject->SetPosition(pos);
467         
468         Py_Return;
469 }         
470
471
472
473 PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObject* kwds)
474 {
475         MT_Vector3 vel;
476         vel[0] = 0.0;
477         vel[1] = 0.0;
478         vel[2] = 0.0;
479
480         if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2]))
481                 return NULL;
482         
483         if (m_soundObject)
484                 m_soundObject->SetVelocity(vel);
485         
486         Py_Return;
487 }         
488
489
490
491 PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyObject* kwds)
492 {
493         MT_Matrix3x3 ori;
494         ori[0][0] = 1.0;
495         ori[0][1] = 0.0;
496         ori[0][2] = 0.0;
497         ori[1][0] = 0.0;
498         ori[1][1] = 1.0;
499         ori[1][2] = 0.0;
500         ori[2][0] = 0.0;
501         ori[2][1] = 0.0;
502         ori[2][2] = 1.0;
503
504         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]))
505                 return NULL;
506         
507         if (m_soundObject)
508                 m_soundObject->SetOrientation(ori);
509         
510         Py_Return;
511 }
512
513 PyObject* KX_SoundActuator::PySetType(PyObject* self, PyObject* args, PyObject* kwds)
514 {
515         int typeArg;
516
517         if (!PyArg_ParseTuple(args, "i", &typeArg)) {
518                 return NULL;
519         }
520
521         if ( (typeArg > KX_SOUNDACT_NODEF)
522           && (typeArg < KX_SOUNDACT_MAX) ) {
523                 m_type = (KX_SOUNDACT_TYPE) typeArg;
524         }
525
526         Py_Return;
527 }
528
529 PyObject* KX_SoundActuator::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
530 {
531         return PyInt_FromLong(m_type);
532 }
533
534
535