5 * ***** BEGIN GPL LICENSE BLOCK *****
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22 * All rights reserved.
24 * The Original Code is: all of this file.
26 * Contributor(s): none yet.
28 * ***** END GPL LICENSE BLOCK *****
32 /** \file gameengine/Ketsji/KX_SoundActuator.cpp
37 #include "KX_SoundActuator.h"
40 # ifdef WITH_EXTERNAL_AUDASPACE
41 typedef float sample_t;
42 # include <audaspace/AUD_Sound.h>
43 # include <audaspace/AUD_Special.h>
44 # include <audaspace/AUD_Device.h>
45 # include <audaspace/AUD_Handle.h>
46 # include <audaspace/python/PyAPI.h>
50 #include "KX_GameObject.h"
51 #include "KX_PyMath.h" // needed for PyObjectFrom()
52 #include "KX_PythonInit.h"
53 #include "KX_Camera.h"
56 /* ------------------------------------------------------------------------- */
57 /* Native functions */
58 /* ------------------------------------------------------------------------- */
59 KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
64 KX_3DSoundSettings settings,
65 KX_SOUNDACT_TYPE type)//,
66 : SCA_IActuator(gameobj, KX_ACT_SOUND)
68 m_sound = AUD_copy(sound);
80 KX_SoundActuator::~KX_SoundActuator()
93 void KX_SoundActuator::play()
104 // this is the sound that will be played and not deleted afterwards
105 AUD_Sound* sound = m_sound;
111 case KX_SOUNDACT_LOOPBIDIRECTIONAL:
112 case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
113 sound = AUD_pingpongSound(sound);
115 case KX_SOUNDACT_LOOPEND:
116 case KX_SOUNDACT_LOOPSTOP:
119 case KX_SOUNDACT_PLAYSTOP:
120 case KX_SOUNDACT_PLAYEND:
125 m_handle = AUD_play(sound, false);
127 // in case of pingpong, we have to free the sound
131 if (m_handle != NULL)
135 AUD_setRelative(m_handle, true);
136 AUD_setVolumeMaximum(m_handle, m_3d.max_gain);
137 AUD_setVolumeMinimum(m_handle, m_3d.min_gain);
138 AUD_setDistanceReference(m_handle, m_3d.reference_distance);
139 AUD_setDistanceMaximum(m_handle, m_3d.max_distance);
140 AUD_setAttenuation(m_handle, m_3d.rolloff_factor);
141 AUD_setConeAngleInner(m_handle, m_3d.cone_inner_angle);
142 AUD_setConeAngleOuter(m_handle, m_3d.cone_outer_angle);
143 AUD_setConeVolumeOuter(m_handle, m_3d.cone_outer_gain);
147 AUD_setLoop(m_handle, -1);
148 AUD_setSoundPitch(m_handle, m_pitch);
149 AUD_setSoundVolume(m_handle, m_volume);
155 CValue* KX_SoundActuator::GetReplica()
157 KX_SoundActuator* replica = new KX_SoundActuator(*this);
158 replica->ProcessReplica();
162 void KX_SoundActuator::ProcessReplica()
164 SCA_IActuator::ProcessReplica();
166 m_sound = AUD_copy(m_sound);
169 bool KX_SoundActuator::Update(double curtime, bool frame)
175 // do nothing on negative events, otherwise sounds are played twice!
176 bool bNegativeEvent = IsNegativeEvent();
177 bool bPositiveEvent = m_posevent;
184 // actual audio device playing state
185 bool isplaying = m_handle ? (AUD_getStatus(m_handle) == AUD_STATUS_PLAYING) : false;
189 // here must be a check if it is still playing
190 if (m_isplaying && isplaying)
194 case KX_SOUNDACT_PLAYSTOP:
195 case KX_SOUNDACT_LOOPSTOP:
196 case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
206 case KX_SOUNDACT_PLAYEND:
208 // do nothing, sound will stop anyway when it's finished
211 case KX_SOUNDACT_LOOPEND:
212 case KX_SOUNDACT_LOOPBIDIRECTIONAL:
214 // stop the looping so that the sound stops when it finished
216 AUD_setLoop(m_handle, 0);
224 // remember that we tried to stop the actuator
229 // Warning: when de-activating the actuator, after a single negative event this runs again with...
230 // m_posevent==false && m_posevent==false, in this case IsNegativeEvent() returns false
231 // and assumes this is a positive event.
232 // check that we actually have a positive event so as not to play sounds when being disabled.
233 else if (bPositiveEvent) /* <- added since 2.49 */
235 else // <- works in most cases except a loop-end sound will never stop unless
236 // the negative pulse is done continuesly
242 // verify that the sound is still playing
243 isplaying = m_handle ? (AUD_getStatus(m_handle) == AUD_STATUS_PLAYING) : false;
249 KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera();
252 KX_GameObject* obj = (KX_GameObject*)this->GetParent();
257 Mo = cam->NodeGetWorldOrientation().inverse();
258 p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition());
261 AUD_setSourceLocation(m_handle, data);
262 p = (obj->GetLinearVelocity() - cam->GetLinearVelocity());
265 AUD_setSourceVelocity(m_handle, data);
266 (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(data);
267 AUD_setSourceOrientation(m_handle, data);
282 /* ------------------------------------------------------------------------- */
283 /* Python functions */
284 /* ------------------------------------------------------------------------- */
288 /* Integration hooks ------------------------------------------------------- */
289 PyTypeObject KX_SoundActuator::Type = {
290 PyVarObject_HEAD_INIT(NULL, 0)
292 sizeof(PyObjectPlus_Proxy),
301 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
306 &SCA_IActuator::Type,
311 PyMethodDef KX_SoundActuator::Methods[] = {
312 KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, startSound),
313 KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, pauseSound),
314 KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, stopSound),
315 {NULL, NULL} //Sentinel
318 PyAttributeDef KX_SoundActuator::Attributes[] = {
319 KX_PYATTRIBUTE_BOOL_RO("is3D", KX_SoundActuator, m_is3d),
320 KX_PYATTRIBUTE_RW_FUNCTION("volume_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
321 KX_PYATTRIBUTE_RW_FUNCTION("volume_minimum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
322 KX_PYATTRIBUTE_RW_FUNCTION("distance_reference", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
323 KX_PYATTRIBUTE_RW_FUNCTION("distance_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
324 KX_PYATTRIBUTE_RW_FUNCTION("attenuation", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
325 KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_inner", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
326 KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
327 KX_PYATTRIBUTE_RW_FUNCTION("cone_volume_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property),
328 KX_PYATTRIBUTE_RW_FUNCTION("sound", KX_SoundActuator, pyattr_get_sound, pyattr_set_sound),
330 KX_PYATTRIBUTE_RW_FUNCTION("time", KX_SoundActuator, pyattr_get_audposition, pyattr_set_audposition),
331 KX_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain),
332 KX_PYATTRIBUTE_RW_FUNCTION("pitch", KX_SoundActuator, pyattr_get_pitch, pyattr_set_pitch),
333 KX_PYATTRIBUTE_ENUM_RW("mode",KX_SoundActuator::KX_SOUNDACT_NODEF+1,KX_SoundActuator::KX_SOUNDACT_MAX-1,false,KX_SoundActuator,m_type),
337 /* Methods ----------------------------------------------------------------- */
338 KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound,
340 "\tStarts the sound.\n")
342 switch (m_handle ? AUD_getStatus(m_handle) : AUD_STATUS_INVALID) {
343 case AUD_STATUS_PLAYING:
345 case AUD_STATUS_PAUSED:
346 AUD_resume(m_handle);
354 KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound,
356 "\tPauses the sound.\n")
363 KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound,
365 "\tStops the sound.\n")
375 /* Atribute setting and getting -------------------------------------------- */
376 PyObject *KX_SoundActuator::pyattr_get_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
378 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
379 const char* prop = attrdef->m_name;
380 float result_value = 0.0;
382 if (!strcmp(prop, "volume_maximum")) {
383 result_value = actuator->m_3d.max_gain;
385 } else if (!strcmp(prop, "volume_minimum")) {
386 result_value = actuator->m_3d.min_gain;
388 } else if (!strcmp(prop, "distance_reference")) {
389 result_value = actuator->m_3d.reference_distance;
391 } else if (!strcmp(prop, "distance_maximum")) {
392 result_value = actuator->m_3d.max_distance;
394 } else if (!strcmp(prop, "attenuation")) {
395 result_value = actuator->m_3d.rolloff_factor;
397 } else if (!strcmp(prop, "cone_angle_inner")) {
398 result_value = actuator->m_3d.cone_inner_angle;
400 } else if (!strcmp(prop, "cone_angle_outer")) {
401 result_value = actuator->m_3d.cone_outer_angle;
403 } else if (!strcmp(prop, "cone_volume_outer")) {
404 result_value = actuator->m_3d.cone_outer_gain;
410 PyObject *result = PyFloat_FromDouble(result_value);
414 PyObject *KX_SoundActuator::pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
416 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
417 float position = 0.0;
419 if (actuator->m_handle)
420 position = AUD_getPosition(actuator->m_handle);
422 PyObject *result = PyFloat_FromDouble(position);
427 PyObject *KX_SoundActuator::pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
429 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
430 float gain = actuator->m_volume;
432 PyObject *result = PyFloat_FromDouble(gain);
437 PyObject *KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
439 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
440 float pitch = actuator->m_pitch;
442 PyObject *result = PyFloat_FromDouble(pitch);
447 PyObject *KX_SoundActuator::pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
449 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
450 if (actuator->m_sound)
451 return (PyObject *)AUD_getPythonSound(actuator->m_sound);
456 int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
458 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
459 const char* prop = attrdef->m_name;
460 float prop_value = 0.0;
462 if (!PyArg_Parse(value, "f", &prop_value))
463 return PY_SET_ATTR_FAIL;
465 // if sound is working and 3D, set the new setting
466 if (!actuator->m_is3d)
467 return PY_SET_ATTR_FAIL;
469 if (!strcmp(prop, "volume_maximum")) {
470 actuator->m_3d.max_gain = prop_value;
471 if (actuator->m_handle)
472 AUD_setVolumeMaximum(actuator->m_handle, prop_value);
474 } else if (!strcmp(prop, "volume_minimum")) {
475 actuator->m_3d.min_gain = prop_value;
476 if (actuator->m_handle)
477 AUD_setVolumeMinimum(actuator->m_handle, prop_value);
479 } else if (!strcmp(prop, "distance_reference")) {
480 actuator->m_3d.reference_distance = prop_value;
481 if (actuator->m_handle)
482 AUD_setDistanceReference(actuator->m_handle, prop_value);
484 } else if (!strcmp(prop, "distance_maximum")) {
485 actuator->m_3d.max_distance = prop_value;
486 if (actuator->m_handle)
487 AUD_setDistanceMaximum(actuator->m_handle, prop_value);
489 } else if (!strcmp(prop, "attenuation")) {
490 actuator->m_3d.rolloff_factor = prop_value;
491 if (actuator->m_handle)
492 AUD_setAttenuation(actuator->m_handle, prop_value);
494 } else if (!!strcmp(prop, "cone_angle_inner")) {
495 actuator->m_3d.cone_inner_angle = prop_value;
496 if (actuator->m_handle)
497 AUD_setConeAngleInner(actuator->m_handle, prop_value);
499 } else if (!strcmp(prop, "cone_angle_outer")) {
500 actuator->m_3d.cone_outer_angle = prop_value;
501 if (actuator->m_handle)
502 AUD_setConeAngleOuter(actuator->m_handle, prop_value);
504 } else if (!strcmp(prop, "cone_volume_outer")) {
505 actuator->m_3d.cone_outer_gain = prop_value;
506 if (actuator->m_handle)
507 AUD_setConeVolumeOuter(actuator->m_handle, prop_value);
510 return PY_SET_ATTR_FAIL;
513 return PY_SET_ATTR_SUCCESS;
516 int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
518 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
520 float position = 1.0;
521 if (!PyArg_Parse(value, "f", &position))
522 return PY_SET_ATTR_FAIL;
524 if (actuator->m_handle)
525 AUD_seek(actuator->m_handle, position);
526 return PY_SET_ATTR_SUCCESS;
529 int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
532 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
533 if (!PyArg_Parse(value, "f", &gain))
534 return PY_SET_ATTR_FAIL;
536 actuator->m_volume = gain;
537 if (actuator->m_handle)
538 AUD_setSoundVolume(actuator->m_handle, gain);
540 return PY_SET_ATTR_SUCCESS;
543 int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
546 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
547 if (!PyArg_Parse(value, "f", &pitch))
548 return PY_SET_ATTR_FAIL;
550 actuator->m_pitch = pitch;
551 if (actuator->m_handle)
552 AUD_setSoundPitch(actuator->m_handle, pitch);
554 return PY_SET_ATTR_SUCCESS;
557 int KX_SoundActuator::pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
559 PyObject *sound = NULL;
560 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
561 if (!PyArg_Parse(value, "O", &sound))
562 return PY_SET_ATTR_FAIL;
564 AUD_Sound *snd = AUD_getSoundFromPython(sound);
568 AUD_unload(actuator->m_sound);
569 actuator->m_sound = snd;
570 return PY_SET_ATTR_SUCCESS;
573 return PY_SET_ATTR_FAIL;
576 #endif // WITH_PYTHON