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