void KX_SoundActuator::play() { if (m_handle) { AUD_Handle_stop(m_handle); m_handle = NULL; } if (!m_sound) return; // this is the sound that will be played and not deleted afterwards AUD_Sound* sound = m_sound; bool loop = false; switch (m_type) { case KX_SOUNDACT_LOOPBIDIRECTIONAL: case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: sound = AUD_Sound_pingpong(sound); ATTR_FALLTHROUGH; case KX_SOUNDACT_LOOPEND: case KX_SOUNDACT_LOOPSTOP: loop = true; break; case KX_SOUNDACT_PLAYSTOP: case KX_SOUNDACT_PLAYEND: default: break; } AUD_Device* device = AUD_Device_getCurrent(); m_handle = AUD_Device_play(device, sound, false); AUD_Device_free(device); // in case of pingpong, we have to free the sound if (sound != m_sound) AUD_Sound_free(sound); if (m_handle != NULL) { if (m_is3d) { AUD_Handle_setRelative(m_handle, true); AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain); AUD_Handle_setVolumeMinimum(m_handle, m_3d.min_gain); AUD_Handle_setDistanceReference(m_handle, m_3d.reference_distance); AUD_Handle_setDistanceMaximum(m_handle, m_3d.max_distance); AUD_Handle_setAttenuation(m_handle, m_3d.rolloff_factor); AUD_Handle_setConeAngleInner(m_handle, m_3d.cone_inner_angle); AUD_Handle_setConeAngleOuter(m_handle, m_3d.cone_outer_angle); AUD_Handle_setConeVolumeOuter(m_handle, m_3d.cone_outer_gain); } if (loop) AUD_Handle_setLoopCount(m_handle, -1); AUD_Handle_setPitch(m_handle, m_pitch); AUD_Handle_setVolume(m_handle, m_volume); } m_isplaying = true; }
bool KX_SoundActuator::Update(double curtime, bool frame) { if (!frame) return true; bool result = false; #ifdef WITH_AUDASPACE // do nothing on negative events, otherwise sounds are played twice! bool bNegativeEvent = IsNegativeEvent(); bool bPositiveEvent = m_posevent; #endif // WITH_AUDASPACE RemoveAllEvents(); #ifdef WITH_AUDASPACE if (!m_sound) return false; // actual audio device playing state bool isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; if (bNegativeEvent) { // here must be a check if it is still playing if (m_isplaying && isplaying) { switch (m_type) { case KX_SOUNDACT_PLAYSTOP: case KX_SOUNDACT_LOOPSTOP: case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: { // stop immediately if (m_handle) { AUD_Handle_stop(m_handle); m_handle = NULL; } break; } case KX_SOUNDACT_PLAYEND: { // do nothing, sound will stop anyway when it's finished break; } case KX_SOUNDACT_LOOPEND: case KX_SOUNDACT_LOOPBIDIRECTIONAL: { // stop the looping so that the sound stops when it finished if (m_handle) AUD_Handle_setLoopCount(m_handle, 0); break; } default: // implement me !! break; } } // remember that we tried to stop the actuator m_isplaying = false; } #if 1 // Warning: when de-activating the actuator, after a single negative event this runs again with... // m_posevent==false && m_posevent==false, in this case IsNegativeEvent() returns false // and assumes this is a positive event. // check that we actually have a positive event so as not to play sounds when being disabled. else if (bPositiveEvent) /* <- added since 2.49 */ #else else // <- works in most cases except a loop-end sound will never stop unless // the negative pulse is done continuesly #endif { if (!m_isplaying) play(); } // verify that the sound is still playing isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; if (isplaying) { if (m_is3d) { KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera(); if (cam) { KX_GameObject* obj = (KX_GameObject*)this->GetParent(); MT_Vector3 p; MT_Matrix3x3 Mo; float data[4]; Mo = cam->NodeGetWorldOrientation().inverse(); p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition()); p = Mo * p; p.getValue(data); AUD_Handle_setLocation(m_handle, data); p = (obj->GetLinearVelocity() - cam->GetLinearVelocity()); p = Mo * p; p.getValue(data); AUD_Handle_setVelocity(m_handle, data); (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(data); AUD_Handle_setOrientation(m_handle, data); } } result = true; } else { m_isplaying = false; result = false; } #endif // WITH_AUDASPACE return result; }