Blender V2.61 - r43446
|
00001 /* 00002 * KX_SoundActuator.cpp 00003 * 00004 * 00005 * ***** BEGIN GPL LICENSE BLOCK ***** 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation; either version 2 00010 * of the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software Foundation, 00019 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 * 00021 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00022 * All rights reserved. 00023 * 00024 * The Original Code is: all of this file. 00025 * 00026 * Contributor(s): none yet. 00027 * 00028 * ***** END GPL LICENSE BLOCK ***** 00029 * 00030 */ 00031 00037 #include "KX_SoundActuator.h" 00038 00039 #ifdef WITH_AUDASPACE 00040 # include "AUD_C-API.h" 00041 # include "AUD_PingPongFactory.h" 00042 # include "AUD_IDevice.h" 00043 # include "AUD_I3DHandle.h" 00044 #endif 00045 00046 #include "KX_GameObject.h" 00047 #include "KX_PyMath.h" // needed for PyObjectFrom() 00048 #include "KX_PythonInit.h" 00049 #include "KX_Camera.h" 00050 #include <iostream> 00051 00052 /* ------------------------------------------------------------------------- */ 00053 /* Native functions */ 00054 /* ------------------------------------------------------------------------- */ 00055 KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, 00056 AUD_Reference<AUD_IFactory> sound, 00057 float volume, 00058 float pitch, 00059 bool is3d, 00060 KX_3DSoundSettings settings, 00061 KX_SOUNDACT_TYPE type)//, 00062 : SCA_IActuator(gameobj, KX_ACT_SOUND) 00063 { 00064 m_sound = sound; 00065 m_volume = volume; 00066 m_pitch = pitch; 00067 m_is3d = is3d; 00068 m_3d = settings; 00069 m_type = type; 00070 m_isplaying = false; 00071 } 00072 00073 00074 00075 KX_SoundActuator::~KX_SoundActuator() 00076 { 00077 if(!m_handle.isNull()) 00078 m_handle->stop(); 00079 } 00080 00081 void KX_SoundActuator::play() 00082 { 00083 if(!m_handle.isNull()) 00084 m_handle->stop(); 00085 00086 if(m_sound.isNull()) 00087 return; 00088 00089 // this is the sound that will be played and not deleted afterwards 00090 AUD_Reference<AUD_IFactory> sound = m_sound; 00091 00092 bool loop = false; 00093 00094 switch (m_type) 00095 { 00096 case KX_SOUNDACT_LOOPBIDIRECTIONAL: 00097 case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: 00098 sound = new AUD_PingPongFactory(sound); 00099 // fall through 00100 case KX_SOUNDACT_LOOPEND: 00101 case KX_SOUNDACT_LOOPSTOP: 00102 loop = true; 00103 break; 00104 case KX_SOUNDACT_PLAYSTOP: 00105 case KX_SOUNDACT_PLAYEND: 00106 default: 00107 break; 00108 } 00109 00110 try 00111 { 00112 m_handle = AUD_getDevice()->play(sound, 0); 00113 } 00114 catch(AUD_Exception&) 00115 { 00116 // cannot play back, ignore 00117 return; 00118 } 00119 00120 AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(m_handle); 00121 00122 if(m_is3d && !handle3d.isNull()) 00123 { 00124 handle3d->setRelative(true); 00125 handle3d->setVolumeMaximum(m_3d.max_gain); 00126 handle3d->setVolumeMinimum(m_3d.min_gain); 00127 handle3d->setDistanceReference(m_3d.reference_distance); 00128 handle3d->setDistanceMaximum(m_3d.max_distance); 00129 handle3d->setAttenuation(m_3d.rolloff_factor); 00130 handle3d->setConeAngleInner(m_3d.cone_inner_angle); 00131 handle3d->setConeAngleOuter(m_3d.cone_outer_angle); 00132 handle3d->setConeVolumeOuter(m_3d.cone_outer_gain); 00133 } 00134 00135 if(loop) 00136 m_handle->setLoopCount(-1); 00137 m_handle->setPitch(m_pitch); 00138 m_handle->setVolume(m_volume); 00139 m_isplaying = true; 00140 } 00141 00142 CValue* KX_SoundActuator::GetReplica() 00143 { 00144 KX_SoundActuator* replica = new KX_SoundActuator(*this); 00145 replica->ProcessReplica(); 00146 return replica; 00147 }; 00148 00149 void KX_SoundActuator::ProcessReplica() 00150 { 00151 SCA_IActuator::ProcessReplica(); 00152 m_handle = AUD_Reference<AUD_IHandle>(); 00153 } 00154 00155 bool KX_SoundActuator::Update(double curtime, bool frame) 00156 { 00157 if (!frame) 00158 return true; 00159 bool result = false; 00160 00161 // do nothing on negative events, otherwise sounds are played twice! 00162 bool bNegativeEvent = IsNegativeEvent(); 00163 bool bPositiveEvent = m_posevent; 00164 00165 RemoveAllEvents(); 00166 00167 if(m_sound.isNull()) 00168 return false; 00169 00170 // actual audio device playing state 00171 bool isplaying = m_handle.isNull() ? false : (m_handle->getStatus() == AUD_STATUS_PLAYING); 00172 00173 if (bNegativeEvent) 00174 { 00175 // here must be a check if it is still playing 00176 if (m_isplaying && isplaying) 00177 { 00178 switch (m_type) 00179 { 00180 case KX_SOUNDACT_PLAYSTOP: 00181 case KX_SOUNDACT_LOOPSTOP: 00182 case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: 00183 { 00184 // stop immediately 00185 if(!m_handle.isNull()) 00186 m_handle->stop(); 00187 m_handle = AUD_Reference<AUD_IHandle>(); 00188 break; 00189 } 00190 case KX_SOUNDACT_PLAYEND: 00191 { 00192 // do nothing, sound will stop anyway when it's finished 00193 break; 00194 } 00195 case KX_SOUNDACT_LOOPEND: 00196 case KX_SOUNDACT_LOOPBIDIRECTIONAL: 00197 { 00198 // stop the looping so that the sound stops when it finished 00199 if(!m_handle.isNull()) 00200 m_handle->setLoopCount(0); 00201 break; 00202 } 00203 default: 00204 // implement me !! 00205 break; 00206 } 00207 } 00208 // remember that we tried to stop the actuator 00209 m_isplaying = false; 00210 } 00211 00212 #if 1 00213 // Warning: when de-activating the actuator, after a single negative event this runs again with... 00214 // m_posevent==false && m_posevent==false, in this case IsNegativeEvent() returns false 00215 // and assumes this is a positive event. 00216 // check that we actually have a positive event so as not to play sounds when being disabled. 00217 else if(bPositiveEvent) { // <- added since 2.49 00218 #else 00219 else { // <- works in most cases except a loop-end sound will never stop unless 00220 // the negative pulse is done continuesly 00221 #endif 00222 if (!m_isplaying) 00223 play(); 00224 } 00225 // verify that the sound is still playing 00226 isplaying = m_handle.isNull() ? false : (m_handle->getStatus() == AUD_STATUS_PLAYING); 00227 00228 if (isplaying) 00229 { 00230 AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(m_handle); 00231 00232 if(m_is3d && !handle3d.isNull()) 00233 { 00234 KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera(); 00235 if (cam) 00236 { 00237 KX_GameObject* obj = (KX_GameObject*)this->GetParent(); 00238 MT_Point3 p; 00239 MT_Matrix3x3 Mo; 00240 AUD_Vector3 v; 00241 float q[4]; 00242 00243 Mo = cam->NodeGetWorldOrientation().inverse(); 00244 p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition()); 00245 p = Mo * p; 00246 p.getValue(v.get()); 00247 handle3d->setSourceLocation(v); 00248 p = (obj->GetLinearVelocity() - cam->GetLinearVelocity()); 00249 p = Mo * p; 00250 p.getValue(v.get()); 00251 handle3d->setSourceVelocity(v); 00252 (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(q); 00253 handle3d->setSourceOrientation(AUD_Quaternion(q[3], q[0], q[1], q[2])); 00254 } 00255 } 00256 result = true; 00257 } 00258 else 00259 { 00260 m_isplaying = false; 00261 result = false; 00262 } 00263 return result; 00264 } 00265 00266 #ifdef WITH_PYTHON 00267 00268 /* ------------------------------------------------------------------------- */ 00269 /* Python functions */ 00270 /* ------------------------------------------------------------------------- */ 00271 00272 00273 00274 /* Integration hooks ------------------------------------------------------- */ 00275 PyTypeObject KX_SoundActuator::Type = { 00276 PyVarObject_HEAD_INIT(NULL, 0) 00277 "KX_SoundActuator", 00278 sizeof(PyObjectPlus_Proxy), 00279 0, 00280 py_base_dealloc, 00281 0, 00282 0, 00283 0, 00284 0, 00285 py_base_repr, 00286 0,0,0,0,0,0,0,0,0, 00287 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 00288 0,0,0,0,0,0,0, 00289 Methods, 00290 0, 00291 0, 00292 &SCA_IActuator::Type, 00293 0,0,0,0,0,0, 00294 py_base_new 00295 }; 00296 00297 PyMethodDef KX_SoundActuator::Methods[] = { 00298 KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, startSound), 00299 KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, pauseSound), 00300 KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, stopSound), 00301 {NULL, NULL} //Sentinel 00302 }; 00303 00304 PyAttributeDef KX_SoundActuator::Attributes[] = { 00305 KX_PYATTRIBUTE_BOOL_RO("is3D", KX_SoundActuator, m_is3d), 00306 KX_PYATTRIBUTE_RW_FUNCTION("volume_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00307 KX_PYATTRIBUTE_RW_FUNCTION("volume_minimum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00308 KX_PYATTRIBUTE_RW_FUNCTION("distance_reference", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00309 KX_PYATTRIBUTE_RW_FUNCTION("distance_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00310 KX_PYATTRIBUTE_RW_FUNCTION("attenuation", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00311 KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_inner", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00312 KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00313 KX_PYATTRIBUTE_RW_FUNCTION("cone_volume_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), 00314 KX_PYATTRIBUTE_RW_FUNCTION("sound", KX_SoundActuator, pyattr_get_sound, pyattr_set_sound), 00315 00316 KX_PYATTRIBUTE_RW_FUNCTION("time", KX_SoundActuator, pyattr_get_audposition, pyattr_set_audposition), 00317 KX_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain), 00318 KX_PYATTRIBUTE_RW_FUNCTION("pitch", KX_SoundActuator, pyattr_get_pitch, pyattr_set_pitch), 00319 KX_PYATTRIBUTE_ENUM_RW("mode",KX_SoundActuator::KX_SOUNDACT_NODEF+1,KX_SoundActuator::KX_SOUNDACT_MAX-1,false,KX_SoundActuator,m_type), 00320 { NULL } //Sentinel 00321 }; 00322 00323 /* Methods ----------------------------------------------------------------- */ 00324 KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound, 00325 "startSound()\n" 00326 "\tStarts the sound.\n") 00327 { 00328 if(!m_handle.isNull()) 00329 { 00330 switch(m_handle->getStatus()) 00331 { 00332 case AUD_STATUS_PLAYING: 00333 break; 00334 case AUD_STATUS_PAUSED: 00335 m_handle->resume(); 00336 break; 00337 default: 00338 play(); 00339 } 00340 } 00341 Py_RETURN_NONE; 00342 } 00343 00344 KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound, 00345 "pauseSound()\n" 00346 "\tPauses the sound.\n") 00347 { 00348 if(!m_handle.isNull()) 00349 m_handle->pause(); 00350 Py_RETURN_NONE; 00351 } 00352 00353 KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound, 00354 "stopSound()\n" 00355 "\tStops the sound.\n") 00356 { 00357 if(!m_handle.isNull()) 00358 m_handle->stop(); 00359 m_handle = AUD_Reference<AUD_IHandle>(); 00360 Py_RETURN_NONE; 00361 } 00362 00363 /* Atribute setting and getting -------------------------------------------- */ 00364 PyObject* KX_SoundActuator::pyattr_get_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) 00365 { 00366 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00367 const char* prop = attrdef->m_name; 00368 float result_value = 0.0; 00369 00370 if(!strcmp(prop, "volume_maximum")) { 00371 result_value = actuator->m_3d.max_gain; 00372 00373 } else if (!strcmp(prop, "volume_minimum")) { 00374 result_value = actuator->m_3d.min_gain; 00375 00376 } else if (!strcmp(prop, "distance_reference")) { 00377 result_value = actuator->m_3d.reference_distance; 00378 00379 } else if (!strcmp(prop, "distance_maximum")) { 00380 result_value = actuator->m_3d.max_distance; 00381 00382 } else if (!strcmp(prop, "attenuation")) { 00383 result_value = actuator->m_3d.rolloff_factor; 00384 00385 } else if (!strcmp(prop, "cone_angle_inner")) { 00386 result_value = actuator->m_3d.cone_inner_angle; 00387 00388 } else if (!strcmp(prop, "cone_angle_outer")) { 00389 result_value = actuator->m_3d.cone_outer_angle; 00390 00391 } else if (!strcmp(prop, "cone_volume_outer")) { 00392 result_value = actuator->m_3d.cone_outer_gain; 00393 00394 } else { 00395 Py_RETURN_NONE; 00396 } 00397 00398 PyObject* result = PyFloat_FromDouble(result_value); 00399 return result; 00400 } 00401 00402 PyObject* KX_SoundActuator::pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) 00403 { 00404 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00405 float position = 0.0; 00406 00407 if(!actuator->m_handle.isNull()) 00408 position = actuator->m_handle->getPosition(); 00409 00410 PyObject* result = PyFloat_FromDouble(position); 00411 00412 return result; 00413 } 00414 00415 PyObject* KX_SoundActuator::pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) 00416 { 00417 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00418 float gain = actuator->m_volume; 00419 00420 PyObject* result = PyFloat_FromDouble(gain); 00421 00422 return result; 00423 } 00424 00425 PyObject* KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) 00426 { 00427 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00428 float pitch = actuator->m_pitch; 00429 00430 PyObject* result = PyFloat_FromDouble(pitch); 00431 00432 return result; 00433 } 00434 00435 PyObject* KX_SoundActuator::pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) 00436 { 00437 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00438 if(!actuator->m_sound.isNull()) 00439 return AUD_getPythonFactory(&actuator->m_sound); 00440 else 00441 Py_RETURN_NONE; 00442 } 00443 00444 int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00445 { 00446 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00447 const char* prop = attrdef->m_name; 00448 float prop_value = 0.0; 00449 00450 if (!PyArg_Parse(value, "f", &prop_value)) 00451 return PY_SET_ATTR_FAIL; 00452 00453 AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(actuator->m_handle); 00454 // if sound is working and 3D, set the new setting 00455 if(!actuator->m_is3d) 00456 return PY_SET_ATTR_FAIL; 00457 00458 if(!strcmp(prop, "volume_maximum")) { 00459 actuator->m_3d.max_gain = prop_value; 00460 if(!handle3d.isNull()) 00461 handle3d->setVolumeMaximum(prop_value); 00462 00463 } else if (!strcmp(prop, "volume_minimum")) { 00464 actuator->m_3d.min_gain = prop_value; 00465 if(!handle3d.isNull()) 00466 handle3d->setVolumeMinimum(prop_value); 00467 00468 } else if (!strcmp(prop, "distance_reference")) { 00469 actuator->m_3d.reference_distance = prop_value; 00470 if(!handle3d.isNull()) 00471 handle3d->setDistanceReference(prop_value); 00472 00473 } else if (!strcmp(prop, "distance_maximum")) { 00474 actuator->m_3d.max_distance = prop_value; 00475 if(!handle3d.isNull()) 00476 handle3d->setDistanceMaximum(prop_value); 00477 00478 } else if (!strcmp(prop, "attenuation")) { 00479 actuator->m_3d.rolloff_factor = prop_value; 00480 if(!handle3d.isNull()) 00481 handle3d->setAttenuation(prop_value); 00482 00483 } else if (!!strcmp(prop, "cone_angle_inner")) { 00484 actuator->m_3d.cone_inner_angle = prop_value; 00485 if(!handle3d.isNull()) 00486 handle3d->setConeAngleInner(prop_value); 00487 00488 } else if (!strcmp(prop, "cone_angle_outer")) { 00489 actuator->m_3d.cone_outer_angle = prop_value; 00490 if(!handle3d.isNull()) 00491 handle3d->setConeAngleOuter(prop_value); 00492 00493 } else if (!strcmp(prop, "cone_volume_outer")) { 00494 actuator->m_3d.cone_outer_gain = prop_value; 00495 if(!handle3d.isNull()) 00496 handle3d->setConeVolumeOuter(prop_value); 00497 00498 } else { 00499 return PY_SET_ATTR_FAIL; 00500 } 00501 00502 return PY_SET_ATTR_SUCCESS; 00503 } 00504 00505 int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00506 { 00507 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00508 00509 float position = 1.0; 00510 if (!PyArg_Parse(value, "f", &position)) 00511 return PY_SET_ATTR_FAIL; 00512 00513 if(!actuator->m_handle.isNull()) 00514 actuator->m_handle->seek(position); 00515 return PY_SET_ATTR_SUCCESS; 00516 } 00517 00518 int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00519 { 00520 float gain = 1.0; 00521 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00522 if (!PyArg_Parse(value, "f", &gain)) 00523 return PY_SET_ATTR_FAIL; 00524 00525 actuator->m_volume = gain; 00526 if(!actuator->m_handle.isNull()) 00527 actuator->m_handle->setVolume(gain); 00528 00529 return PY_SET_ATTR_SUCCESS; 00530 } 00531 00532 int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00533 { 00534 float pitch = 1.0; 00535 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00536 if (!PyArg_Parse(value, "f", &pitch)) 00537 return PY_SET_ATTR_FAIL; 00538 00539 actuator->m_pitch = pitch; 00540 if(!actuator->m_handle.isNull()) 00541 actuator->m_handle->setPitch(pitch); 00542 00543 return PY_SET_ATTR_SUCCESS; 00544 } 00545 00546 int KX_SoundActuator::pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00547 { 00548 PyObject* sound = NULL; 00549 KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); 00550 if (!PyArg_Parse(value, "O", &sound)) 00551 return PY_SET_ATTR_FAIL; 00552 00553 AUD_Reference<AUD_IFactory>* snd = reinterpret_cast<AUD_Reference<AUD_IFactory>*>(AUD_getPythonSound(sound)); 00554 if(snd) 00555 { 00556 actuator->m_sound = *snd; 00557 delete snd; 00558 return PY_SET_ATTR_SUCCESS; 00559 } 00560 00561 return PY_SET_ATTR_FAIL; 00562 } 00563 00564 #endif // WITH_PYTHON