NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

audioService.py (37236B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\client\script\environment\audioService.py
      2 import logging
      3 import sys
      4 import audio2
      5 import trinity
      6 import uthread2
      7 import dogma.const as dogmaconst
      8 import eveaudio
      9 import eveaudio.const as audConst
     10 import eveaudio.immersiveoverlay
     11 import evecamera
     12 from carbon.common.script.sys.service import Service
     13 from eve.client.script.ui.view.viewStateConst import ViewState
     14 from eve.common.script.sys.eveCfg import InShipInSpace
     15 from eve.common.script.sys.idCheckers import IsTriglavianSystem
     16 from eveaudio.eveaudiomanager import CreateAudioManager
     17 from eveaudio.fsdUtils import GetEventFromSoundID
     18 from eveaudio.helpers import CreateAudioObserver
     19 from eveaudio.shiphealthnotification import ShipHealthNotifier
     20 from eveaudio.ui import UIAudioManager
     21 CUSTOM_SOUND_LEVELS_SETTINGS = {'custom_atmosphere': 'advanced_settings_atmosphere',
     22  'custom_jumpactivation': 'advanced_settings_jump_activations',
     23  'custom_secondaryinterfaces': 'advanced_settings_secondary_interfaces',
     24  'custom_shipeffects': 'advanced_settings_ship_effects',
     25  'custom_shipsounds': 'advanced_settings_ship_sounds',
     26  'custom_turrets': 'advanced_settings_turrets',
     27  'custom_warningsfx': 'advanced_settings_warning_sfx',
     28  'custom_uiclick': 'advanced_settings_uiclick'}
     29 DAMPENING_SETTINGS = {'inactiveSounds_master': 'custom_damp_master',
     30  'inactiveSounds_music': 'custom_damp_music',
     31  'inactiveSounds_turrets': 'custom_damp_turrets',
     32  'inactiveSounds_shield': 'custom_damp_shield',
     33  'inactiveSounds_armor': 'custom_damp_armor',
     34  'inactiveSounds_hull': 'custom_damp_hull',
     35  'inactiveSounds_shipsound': 'custom_damp_shipsound',
     36  'inactiveSounds_jumpgates': 'custom_damp_jumpgates',
     37  'inactiveSounds_wormholes': 'custom_damp_wormholes',
     38  'inactiveSounds_jumping': 'custom_damp_jumping',
     39  'inactiveSounds_aura': 'custom_damp_aura',
     40  'inactiveSounds_modules': 'custom_damp_modules',
     41  'inactiveSounds_explosions': 'custom_damp_explosions',
     42  'inactiveSounds_warping': 'custom_damp_warping',
     43  'inactiveSounds_locking': 'custom_damp_locking',
     44  'inactiveSounds_planets': 'custom_damp_planets',
     45  'inactiveSounds_impacts': 'custom_damp_impacts',
     46  'inactiveSounds_deployables': 'custom_damp_deployables',
     47  'inactiveSounds_boosters': 'custom_damp_boosters',
     48  'inactiveSounds_stationint': 'custom_damp_stationint',
     49  'inactiveSounds_stationext': 'custom_damp_stationext',
     50  'inactiveSounds_structures': 'custom_damp_structures'}
     51 INDUSTRY_LEVELS = {i:u'set_industry_level_%s_state' % (i,) for i in xrange(6)}
     52 RESEARCH_LEVELS = {i:u'set_research_level_%s_state' % (i,) for i in xrange(6)}
     53 logger = logging.getLogger('audioSvc')
     54 
     55 def GetAudioService():
     56     return sm.GetService('audio')
     57 
     58 
     59 class AudioService(Service):
     60     __guid__ = 'svc.audio'
     61     __exportedcalls__ = {'Activate': [],
     62      'Deactivate': [],
     63      'GetMasterVolume': [],
     64      'SetMasterVolume': [],
     65      'GetUIVolume': [],
     66      'SetUIVolume': [],
     67      'GetWorldVolume': [],
     68      'SetWorldVolume': [],
     69      'GetVoiceVolume': [],
     70      'SetVoiceVolume': [],
     71      'GetCombatMusicUsage': [],
     72      'MuteSounds': [],
     73      'UnmuteSounds': [],
     74      'IsActivated': [],
     75      'AudioMessage': [],
     76      'GetDialoguePlayPosition': [],
     77      'LoadBanksForView': [],
     78      'PostDialogueEvent': [],
     79      'SendUIEvent': [],
     80      'SendUIEventWithCallback': [],
     81      'SetUIRTPC': [],
     82      'StartSoundLoop': [],
     83      'StopSoundLoop': [],
     84      'SubscribeToEventCallback': [],
     85      'UnsubscribeFromEventCallback': [],
     86      'BallSupportsAudio': [],
     87      'ItemSupportsAudio': [],
     88      'GetAudioEmittersOnItem': [],
     89      'GetOrCreateAudioEmitterForItem': [],
     90      'PlayEventOnItem': [],
     91      'PlaySoundOnItem': [],
     92      'StopEventOnItem': [],
     93      'StopSoundOnItem': [],
     94      'GetTurretSuppression': [],
     95      'SetTurretSuppression': [],
     96      'SetShipState': [],
     97      'SetupPlanet3DAudio': [],
     98      'WarpPreparation': [],
     99      'EnableDebugShowAllEmitters': [],
    100      'DisableDebugShowAllEmitters': [],
    101      'GetDebugDisplayAllEmitters': [],
    102      'SeekOnEventPercent': [],
    103      'SeekOnEventMs': [],
    104      'SetGameParameterOnAudioEmitter': [],
    105      'DisableSpatialAudio': [],
    106      'EnableSpatialAudio': [],
    107      'SpatialAudioEnabled': [],
    108      'SpatialAudioIsSupported': []}
    109     __startupdependencies__ = ['settings', 'sceneManager', 'dynamicMusic']
    110     __dependencies__ = ['map', 'michelle']
    111     __notifyevents__ = ['DoBallsAdded',
    112      'DoBallsRemove',
    113      'OnActiveCameraChanged',
    114      'OnBallparkCall',
    115      'OnBallparkSetState',
    116      'OnCapacitorChange',
    117      'OnChannelsJoined',
    118      'OnClientEvent_ActivateModule',
    119      'OnClientEvent_DeactivateModule',
    120      'OnClientEvent_StopShip',
    121      'OnDamageStateChange',
    122      'OnDogmaItemChange',
    123      'OnDungeonTriggerAmbientSound',
    124      'OnDungeonEntered',
    125      'OnExitingDungeon',
    126      'OnIntroCompleted',
    127      'OnIntroStarted',
    128      'OnPlanetViewChanged',
    129      'OnProvingGroundsMatchFound',
    130      'OnViewStateChanged',
    131      'OnSessionChanged',
    132      'OnSessionReset',
    133      'OnSpecialFX',
    134      'OnWarpArrived',
    135      'OnWarpDecelerate',
    136      'OnClientEvent_WarpFinished']
    137     __componentTypes__ = ['audioEmitter']
    138 
    139     def __init__(self):
    140         Service.__init__(self)
    141         languageID = 'en' if self.AppGetSetting('forceEnglishVoice', False) else session.languageID
    142         self.manager = CreateAudioManager('res:/Audio/', languageID, 'Eve Client')
    143         self.soundLoops = {}
    144         self.lastLookedAt = None
    145         self.shipHealthNotifier = ShipHealthNotifier(self.SendWiseEvent, self.SetGlobalRTPC)
    146         self.lastSystemID = None
    147         self.lastCameraID = None
    148         self.shipState = None
    149         self.uiAudioManager = None
    150         self.immersiveOverlayManager = None
    151         self.activeAmbientDungeonSounds = []
    152         self.numEntitiesInPark = 0
    153         self.engineLimit = 0
    154 
    155     def Run(self, ms = None):
    156         self.active = False
    157         self.uiAudioManager = UIAudioManager()
    158         self.jukeboxPlayer = None
    159         self.immersiveOverlayManager = eveaudio.immersiveoverlay.Manager(send_audio_event=self.SendUIEvent)
    160         uthread2.StartTasklet(self._WatchActiveWindow)
    161         if self.AppGetSetting('audioEnabled', 1):
    162             self.Activate()
    163 
    164     def Stop(self, stream):
    165         self.uiAudioManager = None
    166         self.jukeboxPlayer = None
    167 
    168     def SetGlobalRTPC(self, rtpcName, value):
    169         if not self.IsActivated():
    170             return
    171         self.manager.SetGlobalRTPC(rtpcName, value)
    172 
    173     def SetGlobalState(self, stateGroup, stateName):
    174         if not self.IsActivated():
    175             return
    176         self.manager.SetState(unicode(stateGroup), unicode(stateName))
    177 
    178     def Activate(self):
    179         self.manager.Enable()
    180         self.active = True
    181         self.ApplySettings()
    182         sm.ScatterEvent('OnAudioActivated')
    183         self.manager.RegisterAudioDeviceChangeCallback(self.UserAudioDeviceChangeCallback)
    184 
    185     def Deactivate(self):
    186         self.manager.Disable()
    187         self.activeAmbientDungeonSounds = []
    188         self.active = False
    189         sm.ScatterEvent('OnAudioDeactivated')
    190 
    191     def ApplySettings(self):
    192         self.SetMasterVolume(self.GetMasterVolume())
    193         self.SetUIVolume(self.GetUIVolume())
    194         self.SetWorldVolume(self.GetWorldVolume())
    195         self.SetVoiceVolume(self.GetVoiceVolume())
    196         self._SetAmpVolume(self.GetMusicVolume())
    197         self.SetTurretSuppression(self.GetTurretSuppression())
    198         self.SetOldJukeboxOverride(self.GetOldJukeboxOverride())
    199         self.SetCombatMusicUsage(self.GetCombatMusicUsage())
    200         if settings.user.audio.Get('soundLevel_advancedSettings', False):
    201             self.LoadUpSavedAdvancedSettings()
    202 
    203     def SetMasterVolume(self, vol = 1.0, persist = True):
    204         if vol < 0.0 or vol > 1.0:
    205             raise RuntimeError('Erroneous value received for volume')
    206         self.SetGlobalRTPC(unicode('volume_master'), vol)
    207         if persist:
    208             self.AppSetSetting('masterVolume', vol)
    209 
    210     def GetMasterVolume(self):
    211         return self.AppGetSetting('masterVolume', 0.7)
    212 
    213     def SetUIVolume(self, vol = 1.0, persist = True):
    214         if vol < 0.0 or vol > 1.0:
    215             raise RuntimeError('Erroneous value received for volume')
    216         self.SetGlobalRTPC(unicode('volume_ui'), vol)
    217         if persist:
    218             self.AppSetSetting('uiGain', vol)
    219 
    220     def GetUIVolume(self):
    221         return self.AppGetSetting('uiGain', 0.5)
    222 
    223     def SetWorldVolume(self, vol = 1.0, persist = True):
    224         if vol < 0.0 or vol > 1.0:
    225             raise RuntimeError('Erroneous value received for volume')
    226         self.SetGlobalRTPC(unicode('volume_world'), vol)
    227         if persist:
    228             self.AppSetSetting('worldVolume', vol)
    229 
    230     def SetCustomValue(self, vol, settingName, persist = True):
    231         rtpcConfigName = CUSTOM_SOUND_LEVELS_SETTINGS.get(settingName)
    232         if not rtpcConfigName:
    233             return
    234         self.SetSoundVolumeBetween0and1(volume=vol, configNameRTPC=rtpcConfigName, configNameAppSetting=settingName, persist=persist)
    235 
    236     def SetSoundVolumeBetween0and1(self, volume, configNameRTPC, configNameAppSetting, persist):
    237         if volume is None:
    238             volume = settings.user.audio.Get(configNameAppSetting, 0.5)
    239         if volume < 0.0 or volume > 1.0:
    240             raise RuntimeError('Erroneous value received for volume, configName=', configNameAppSetting)
    241         self.SetGlobalRTPC(unicode(configNameRTPC), volume)
    242         if persist:
    243             settings.user.audio.Set(configNameAppSetting, volume)
    244 
    245     def EnableAdvancedSettings(self):
    246         for eachSettingName in CUSTOM_SOUND_LEVELS_SETTINGS.iterkeys():
    247             self.SetCustomValue(vol=None, settingName=eachSettingName, persist=False)
    248 
    249     def DisableAdvancedSettings(self):
    250         for eachSettingName in CUSTOM_SOUND_LEVELS_SETTINGS.iterkeys():
    251             self.SetCustomValue(vol=0.5, settingName=eachSettingName, persist=False)
    252 
    253     def LoadUpSavedAdvancedSettings(self):
    254         for eachSettingName in CUSTOM_SOUND_LEVELS_SETTINGS.iterkeys():
    255             volume = settings.user.audio.Get(eachSettingName, 0.5)
    256             self.SetCustomValue(vol=volume, settingName=eachSettingName, persist=False)
    257 
    258     def SetDampeningValue(self, settingName, setOn = True):
    259         audioEvent = DAMPENING_SETTINGS.get(settingName)
    260         if not audioEvent:
    261             return
    262         if setOn:
    263             audioEvent += '_on'
    264         else:
    265             audioEvent += '_off'
    266         self.uiAudioManager.SendUIEvent(audioEvent)
    267 
    268     def SetDampeningValueSetting(self, settingName, setOn = True):
    269         settings.user.audio.Set(settingName, setOn)
    270 
    271     def DisableDampeningValues(self):
    272         for eachSettingName in DAMPENING_SETTINGS.iterkeys():
    273             self.SetDampeningValue(settingName=eachSettingName, setOn=False)
    274 
    275     def LoadUpSavedDampeningValues(self):
    276         for eachSettingName in DAMPENING_SETTINGS.iterkeys():
    277             setOn = settings.user.audio.Get(eachSettingName, False)
    278             self.SetDampeningValue(settingName=eachSettingName, setOn=setOn)
    279 
    280     def GetWorldVolume(self):
    281         return self.AppGetSetting('worldVolume', 0.7)
    282 
    283     def SetVoiceVolume(self, vol = 1.0, persist = True):
    284         if vol < 0.0 or vol > 1.0:
    285             raise RuntimeError('Erroneous value received for volume')
    286         if not self.IsActivated():
    287             return
    288         self.SetGlobalRTPC('volume_voice', vol)
    289         if persist:
    290             self.AppSetSetting('evevoiceGain', vol)
    291 
    292     def GetVoiceVolume(self):
    293         return self.AppGetSetting('evevoiceGain', 0.9)
    294 
    295     def _SetAmpVolume(self, volume = 0.5, persist = True):
    296         if volume < 0.0 or volume > 1.0:
    297             raise RuntimeError('Erroneous value received for volume')
    298         if not self.IsActivated():
    299             return
    300         self.SetGlobalRTPC('volume_music', volume)
    301         if persist:
    302             self.AppSetSetting('eveampGain', volume)
    303 
    304     def UserSetAmpVolume(self, volume = 0.5, persist = True):
    305         self._SetAmpVolume(volume, persist)
    306         sm.GetService('dynamicMusic').MusicVolumeChangedByUser(volume)
    307 
    308     def GetMusicVolume(self):
    309         return self.AppGetSetting('eveampGain', 0.5)
    310 
    311     def IsActivated(self):
    312         return self.active
    313 
    314     def HandleFsdSoundID(self, soundID, emitter = None):
    315         if emitter:
    316             event = GetEventFromSoundID(soundID)
    317             if event:
    318                 return emitter.SendEvent(event)
    319         else:
    320             self.LogError('FSD sound ID {} was passed in without a corresponding emitter.'.format(soundID))
    321         return 0
    322 
    323     def SendUIEvent(self, event):
    324         if not self.IsActivated():
    325             return
    326         return self.uiAudioManager.SendUIEvent(event)
    327 
    328     def StopUIEvent(self, playingID):
    329         self.uiAudioManager.StopUIEvent(playingID)
    330 
    331     def SendUIEventByTypeID(self, typeID):
    332         self.uiAudioManager.SendUIEventByTypeID(typeID)
    333 
    334     def PostDialogueEvent(self, event):
    335         self.uiAudioManager.PostDialogueEvent(event)
    336 
    337     def AppGetSetting(self, setting, default):
    338         try:
    339             return settings.public.audio.Get(setting, default)
    340         except (AttributeError, NameError):
    341             return default
    342 
    343     def AppSetSetting(self, setting, value):
    344         try:
    345             settings.public.audio.Set(setting, value)
    346         except (AttributeError, NameError):
    347             pass
    348 
    349     def AudioMessage(self, msg, msgKey = None):
    350         if not self.IsActivated():
    351             return
    352         self.uiAudioManager.SendAudioMessage(msg, userErrorKey=msgKey)
    353 
    354     def StartSoundLoop(self, rootLoopMsg):
    355         if not self.IsActivated():
    356             return
    357         try:
    358             if rootLoopMsg not in self.soundLoops:
    359                 self.LogInfo('StartSoundLoop starting loop with root %s' % rootLoopMsg)
    360                 self.soundLoops[rootLoopMsg] = 1
    361                 self.uiAudioManager.SendUIEvent('msg_%s_play' % rootLoopMsg)
    362             else:
    363                 self.soundLoops[rootLoopMsg] += 1
    364                 self.LogInfo('StartSoundLoop incrementing %s loop to %d' % (rootLoopMsg, self.soundLoops[rootLoopMsg]))
    365         except:
    366             self.LogWarn('StartSoundLoop failed - halting loop with root', rootLoopMsg)
    367             self.uiAudioManager.SendUIEvent('msg_%s_stop' % rootLoopMsg)
    368             sys.exc_clear()
    369 
    370     def StopSoundLoop(self, rootLoopMsg, eventMsg = None):
    371         if rootLoopMsg not in self.soundLoops:
    372             self.LogInfo('StopSoundLoop told to halt', rootLoopMsg, 'but that message is not playing!')
    373             return
    374         try:
    375             self.soundLoops[rootLoopMsg] -= 1
    376             if self.soundLoops[rootLoopMsg] <= 0:
    377                 self.LogInfo('StopSoundLoop halting message with root', rootLoopMsg)
    378                 del self.soundLoops[rootLoopMsg]
    379                 self.uiAudioManager.SendUIEvent('msg_%s_stop' % rootLoopMsg)
    380             else:
    381                 self.LogInfo('StopSoundLoop decremented count of loop with root %s to %d' % (rootLoopMsg, self.soundLoops[rootLoopMsg]))
    382         except:
    383             self.LogWarn('StopSoundLoop failed due to an exception - forcibly halting', rootLoopMsg)
    384             self.uiAudioManager.SendUIEvent('msg_%s_stop' % rootLoopMsg)
    385             sys.exc_clear()
    386 
    387         if eventMsg is not None:
    388             self.uiAudioManager.SendUIEvent(eventMsg)
    389 
    390     def SetupPlanet3DAudio(self, planet, typeID):
    391         if typeID in audConst.PLANET_3D_AUDIO_TRIGGERS.keys():
    392             events = [audConst.PLANET_3D_AUDIO_TRIGGERS[typeID]]
    393             if IsTriglavianSystem(session.solarsystemid2):
    394                 events.append(audConst.TRIG_PLANET_3D_TRIGGER)
    395             observer = CreateAudioObserver('planet_atmosphere')
    396             observer.observer.SetAttenuationScalingFactor(planet.radius)
    397             [ observer.observer.SendEvent(event) for event in events ]
    398             planet.observers.append(observer)
    399 
    400     def GetTurretSuppression(self):
    401         return self.AppGetSetting('suppressTurret', 0)
    402 
    403     def SetTurretSuppression(self, suppress, persist = True):
    404         if not self.IsActivated():
    405             return
    406         if suppress:
    407             self.SetGlobalRTPC('turret_muffler', 0.0)
    408             suppress = 1
    409         else:
    410             self.SetGlobalRTPC('turret_muffler', 1.0)
    411             suppress = 0
    412         if persist:
    413             self.AppSetSetting('suppressTurret', suppress)
    414 
    415     def GetOldJukeboxOverride(self):
    416         return self.AppGetSetting('useOldJukeboxOverride', 0)
    417 
    418     def SetOldJukeboxOverride(self, useClassicMusic):
    419         self.AppSetSetting('useOldJukeboxOverride', useClassicMusic)
    420 
    421     def GetCombatMusicUsage(self):
    422         return self.AppGetSetting('useCombatMusic', 1)
    423 
    424     def SetCombatMusicUsage(self, useCombatMusic):
    425         self.AppSetSetting('useCombatMusic', useCombatMusic)
    426 
    427     def MuteSounds(self):
    428         self.SetMasterVolume(0.0, False)
    429 
    430     def UnmuteSounds(self):
    431         self.SetMasterVolume(self.GetMasterVolume(), False)
    432 
    433     def SendWiseEvent(self, event):
    434         if event:
    435             self.uiAudioManager.SendUIEvent(event)
    436 
    437     def OnChannelsJoined(self, channelIDs):
    438         if not session.stationid:
    439             return
    440         if (('solarsystemid2', session.solarsystemid2),) in channelIDs:
    441             pilotsInChannel = eveaudio.GetPilotsInSystem()
    442             self.SetHangarPopulationSwitch(pilotsInChannel)
    443 
    444     def OnClientEvent_ActivateModule(self, effectID):
    445         if effectID == dogmaconst.effectModuleBonusMicrowarpdrive:
    446             self._SetControllerVariableOnShip(audConst.ModuleType.__name__, audConst.ModuleType.microwarpdrive.value)
    447         elif effectID == dogmaconst.effectModuleBonusAfterburner:
    448             self._SetControllerVariableOnShip(audConst.ModuleType.__name__, audConst.ModuleType.afterburner.value)
    449         self._SetControllerVariableOnShip(audConst.ModuleState.__name__, audConst.ModuleState.activated.value)
    450 
    451     def OnClientEvent_DeactivateModule(self, effectID):
    452         if effectID == dogmaconst.effectModuleBonusMicrowarpdrive:
    453             self._SetControllerVariableOnShip(audConst.ModuleType.__name__, audConst.ModuleType.microwarpdrive.value)
    454         elif effectID == dogmaconst.effectModuleBonusAfterburner:
    455             self._SetControllerVariableOnShip(audConst.ModuleType.__name__, audConst.ModuleType.afterburner.value)
    456         self._SetControllerVariableOnShip(audConst.ModuleState.__name__, audConst.ModuleState.powerdown.value)
    457 
    458     def OnClientEvent_StopShip(self):
    459         self._SetControllerVariableOnShip(audConst.STOP_SHIP_CTRL_VARIABLE, 1)
    460 
    461     def SetHangarPopulationSwitch(self, pilotsInChannel):
    462         self.uiAudioManager.SendUIEvent(eveaudio.GetHangarPopulationSwitch(pilotsInChannel))
    463 
    464     def SwapBanks(self, banks):
    465         self.manager.SwapSoundBanks(banks)
    466 
    467     def ReloadBanks(self):
    468         soundBankStatus = self.manager.ReloadSoundBanks()
    469         self.ApplySettings()
    470         return soundBankStatus
    471 
    472     def OnDamageStateChange(self, *args, **kwargs):
    473         return self.shipHealthNotifier.OnDamageStateChange(*args, **kwargs)
    474 
    475     def OnCapacitorChange(self, *args, **kwargs):
    476         return self.shipHealthNotifier.OnCapacitorChange(*args, **kwargs)
    477 
    478     def OnSessionChanged(self, isRemote, session, change):
    479         if 'userid' in change and session.userid:
    480             self.ApplySettings()
    481         if not session.stationid:
    482             if 'solarsystemid' in change:
    483                 oldSolarSystem, newSolarSystem = change['solarsystemid']
    484                 if oldSolarSystem and newSolarSystem:
    485                     eveaudio.PlaySystemSpecificEntrySound(self.lastSystemID, session.solarsystemid2, self.uiAudioManager.GetUIEmitter())
    486             self.lastSystemID = session.solarsystemid2
    487         if 'shipid' in change:
    488             oldShipID, newShipID = change['shipid']
    489             self._SetControllerVariableOnShip(audConst.ActingParty.__name__, audConst.ActingParty.firstParty.value, shipID=newShipID)
    490             self._SetControllerVariableOnShip(audConst.ActingParty.__name__, audConst.ActingParty.thirdParty.value, shipID=oldShipID)
    491 
    492     def OnSessionReset(self):
    493         self.StopAllAudio()
    494         self.numEntitiesInPark = 0
    495         self.activeAmbientDungeonSounds = []
    496 
    497     def StopAllAudio(self):
    498         self.manager.manager.StopAll()
    499 
    500     def OnSpecialFX(self, shipID, moduleID, moduleTypeID, targetID, otherTypeID, guid, isOffensive, start, active, *args, **kwargs):
    501         if guid == audConst.MICROWARPDRIVE_GUID or guid == audConst.AFTERBURNER_GUID:
    502             if guid == audConst.MICROWARPDRIVE_GUID:
    503                 self._SetControllerVariableOnShip(audConst.ModuleType.__name__, audConst.ModuleType.microwarpdrive.value, shipID=shipID)
    504             else:
    505                 self._SetControllerVariableOnShip(audConst.ModuleType.__name__, audConst.ModuleType.afterburner.value, shipID=shipID)
    506             if not start:
    507                 self._SetControllerVariableOnShip(audConst.ModuleState.__name__, audConst.ModuleState.deactivated.value, shipID=shipID)
    508             else:
    509                 self._SetControllerVariableOnShip(audConst.ModuleState.__name__, audConst.ModuleState.activated.value, shipID=shipID)
    510         elif guid == audConst.WARPING_GUID:
    511             if shipID != session.shipid:
    512                 self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.prep.value, shipID=shipID)
    513 
    514     def LoadBanksForView(self, newView):
    515         if newView == ViewState.Hangar:
    516             self.SetGlobalState('in_hangar', 'yes')
    517             self.SwapBanks(eveaudio.EVE_HANGAR_BANKS)
    518             eveaudio.SetTheraSystemHangarSwitch(session.solarsystemid2, self.uiAudioManager.GetUIEmitter())
    519         elif newView == ViewState.Space:
    520             self.SwapBanks(eveaudio.EVE_SPACE_BANKS)
    521         if newView != ViewState.Hangar:
    522             self.SetGlobalState('in_hangar', 'no')
    523 
    524     def _WatchActiveWindow(self):
    525         isActive = None
    526         while True:
    527             if settings.user.audio.Get('inactiveSounds_advancedSettings', False):
    528                 if trinity.app.IsActive() != isActive:
    529                     isActive = trinity.app.IsActive()
    530                     if isActive:
    531                         self.DisableDampeningValues()
    532                     else:
    533                         self.LoadUpSavedDampeningValues()
    534             uthread2.Sleep(0.3)
    535 
    536     def OnBallparkSetState(self):
    537         self.SetResearchAndIndustryLevel()
    538 
    539     def SetResearchAndIndustryLevel(self):
    540         ballpark = sm.GetService('michelle').GetBallpark()
    541         if ballpark is None:
    542             return
    543         industryLevel = ballpark.industryLevel
    544         researchLevel = ballpark.researchLevel
    545         if industryLevel in INDUSTRY_LEVELS.keys():
    546             self.uiAudioManager.SendUIEvent(INDUSTRY_LEVELS.get(industryLevel))
    547         if researchLevel in RESEARCH_LEVELS.keys():
    548             self.uiAudioManager.SendUIEvent(RESEARCH_LEVELS.get(researchLevel))
    549 
    550     def OnDogmaItemChange(self, *args, **kwargs):
    551         if not InShipInSpace():
    552             return
    553         shipid = session.shipid
    554         ship = sm.StartService('godma').GetItem(shipid)
    555         if shipid and ship:
    556             cargoHoldState = ship.GetCapacity()
    557             return self.shipHealthNotifier.OnCargoHoldChange(shipid, cargoHoldState, *args, **kwargs)
    558 
    559     def OnDungeonTriggerAmbientSound(self, dungeonID, soundID, entityItemID):
    560         logger.info('Ambient sound {} was requested to play in dungeon {} on item {}'.format(soundID, dungeonID, entityItemID))
    561         emitterID = self.PlaySoundOnItem(soundID, entityItemID)
    562         if emitterID > 0:
    563             self.activeAmbientDungeonSounds.append((emitterID, soundID))
    564 
    565     def OnDungeonEntered(self, dungeonID, instanceID):
    566         self.activeAmbientDungeonSounds = []
    567 
    568     def OnExitingDungeon(self, dungeonID):
    569         if self.activeAmbientDungeonSounds:
    570             for emitterID, soundID in self.activeAmbientDungeonSounds:
    571                 stopped = self.StopSoundOnEmitter(soundID, emitterID)
    572                 if stopped:
    573                     logger.info('Ambient sound {} was stopped for dungeon {}'.format(soundID, dungeonID))
    574 
    575             self.activeAmbientDungeonSounds = []
    576 
    577     def OnIntroCompleted(self):
    578         self.SetGlobalState(*audConst.VIDEO_OVERLAY_STATE_OFF)
    579 
    580     def OnIntroStarted(self):
    581         self.SetGlobalState(*audConst.VIDEO_OVERLAY_STATE_ON)
    582 
    583     def OnPlanetViewChanged(self, planetID, oldPlanetID):
    584         events = []
    585         if planetID and not oldPlanetID:
    586             planetData = self.map.GetPlanetInfo(planetID)
    587             events.append(audConst.PI_AUDIO_TRIGGERS.get(planetData.typeID))
    588             if IsTriglavianSystem(session.solarsystemid2):
    589                 events.append(audConst.TRIG_PLANET_PI_TRIGGER)
    590         elif oldPlanetID and not planetID:
    591             planetData = self.map.GetPlanetInfo(oldPlanetID)
    592             events.append(audConst.PI_AUDIO_TRIGGERS.get(planetData.typeID).replace('play', 'stop'))
    593             if IsTriglavianSystem(session.solarsystemid2):
    594                 events.append(audConst.TRIG_PLANET_PI_TRIGGER.replace('play', 'stop'))
    595         [ self.uiAudioManager.SendUIEvent(event) for event in events ]
    596 
    597     def OnProvingGroundsMatchFound(self):
    598         self.uiAudioManager.SendUIEvent(audConst.UI_AUDIO_TRIGGERS['arena_opponent_matched'] + '_play')
    599 
    600     def OnViewStateChanged(self, fromView, toView):
    601         self.numEntitiesInPark = 0
    602 
    603     def DoBallsAdded(self, ballsToAdd):
    604         numEntities = 0
    605         for ball, slimItem in ballsToAdd:
    606             if getattr(slimItem, 'categoryID', None) in audConst.ENGINE_LIMITING_CATEGORIES:
    607                 numEntities += 1
    608 
    609         self.numEntitiesInPark += numEntities
    610         self._LimitEnginesIfNeeded()
    611 
    612     def DoBallsRemove(self, pythonBalls, isRelease):
    613         numEntities = 0
    614         for ball, slimItem, terminal in pythonBalls:
    615             if getattr(slimItem, 'categoryID', None) in audConst.ENGINE_LIMITING_CATEGORIES:
    616                 numEntities += 1
    617 
    618         self.numEntitiesInPark -= numEntities
    619         self._LimitEnginesIfNeeded()
    620 
    621     def OnActiveCameraChanged(self, cameraID):
    622         if session is None or self.lastCameraID == cameraID:
    623             return
    624         self.uiAudioManager.SendUIEvent('ship_camera_sounds_stop')
    625         if cameraID == evecamera.CAM_TACTICAL:
    626             self.uiAudioManager.SendUIEvent('state_camera_set_overview')
    627         elif cameraID == evecamera.CAM_SHIPPOV:
    628             if hasattr(session, 'shipid') and session.shipid is not None:
    629                 ship = sm.GetService('michelle').GetItem(session.shipid)
    630                 if ship:
    631                     self.uiAudioManager.SendUIEvent('state_camera_set_cockpit')
    632         else:
    633             self.uiAudioManager.SendUIEvent('state_camera_set_normal')
    634 
    635     def SetUIRTPC(self, rtpcName, value):
    636         self.uiAudioManager.SetUIRTPC(rtpcName, value)
    637 
    638     def WarpPreparation(self, action, shipID):
    639         ball = sm.GetService('michelle').GetBall(shipID)
    640         if action == 'play':
    641             if not self.GetShipState() == audConst.ShipState.preparing_warp:
    642                 self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.prep.value, ball=ball, shipID=shipID)
    643                 self.uiAudioManager.SendUIEvent(audConst.UI_AUDIO_TRIGGERS['warp_prep'] + '_play')
    644                 self.AudioMessage('', msgKey='WarpDriveActive')
    645                 self.SetShipState(audConst.ShipState.preparing_warp)
    646         if action == 'stop':
    647             if self.GetShipState() == audConst.ShipState.preparing_warp:
    648                 self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.start.value, ball=ball, shipID=shipID)
    649                 self.uiAudioManager.SendUIEvent(audConst.UI_AUDIO_TRIGGERS['warp_prep'] + '_stop')
    650                 self.SetShipState(audConst.ShipState.warping)
    651         if action == 'cancel':
    652             if self.GetShipState() == audConst.ShipState.preparing_warp:
    653                 self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.stop.value, ball=ball, shipID=shipID)
    654                 self.uiAudioManager.SendUIEvent(audConst.UI_AUDIO_TRIGGERS['warp_prep_abort'] + '_play')
    655                 self.SetShipState(audConst.ShipState.idle)
    656 
    657     def SetShipState(self, value):
    658         self.shipState = value
    659 
    660     def GetShipState(self):
    661         return self.shipState
    662 
    663     def SendUIEventWithCallback(self, event):
    664         return self.uiAudioManager.SendUIEventWithCallback(unicode(event))
    665 
    666     def SubscribeToEventCallback(self, callbackFunc):
    667         self.uiAudioManager.SubscribeToEventCallback(callbackFunc)
    668 
    669     def UnsubscribeFromEventCallback(self, callbackFunc):
    670         self.uiAudioManager.UnsubscribeFromEventCallback(callbackFunc)
    671 
    672     def OnBallparkCall(self, funcname, args):
    673         if args[0] == session.shipid:
    674             if funcname == 'WarpTo':
    675                 self.WarpPreparation('play', args[0])
    676             if funcname == 'Stop':
    677                 self.WarpPreparation('cancel', args[0])
    678 
    679     def OnWarpArrived(self, *args):
    680         self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.decelerate.value)
    681 
    682     def OnWarpDecelerate(self, warpToItemID, warpToTypeID):
    683         self.uiAudioManager.SendUIEvent('ship_warp_wind_end')
    684         self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.stop.value)
    685 
    686     def OnClientEvent_WarpFinished(self, warpToItemID, warpToTypeID):
    687         self._SetControllerVariableOnShip(audConst.WarpState.__name__, audConst.WarpState.finished.value)
    688 
    689     def PlayEventOnItem(self, event, itemID, emitterName = '3d_sfx', maxTries = 10, sleepTime = 0.5):
    690         ball = self._GetAndWaitForBall(itemID, maxTries=maxTries, sleepTime=sleepTime)
    691         if ball:
    692             audioEmitter = self.GetOrCreateAudioEmitterForItem(itemID, emitterName=emitterName, ball=ball)
    693             if audioEmitter:
    694                 playingID = audioEmitter.SendEvent(event)
    695                 if playingID > 0:
    696                     return audioEmitter.ID
    697         return 0
    698 
    699     def StopEventOnItem(self, event, itemID):
    700         audioEmitters = self.GetAudioEmittersOnItem(itemID)
    701         stopped = False
    702         for emitter in audioEmitters:
    703             stopped = emitter.StopEvent(event)
    704             if stopped:
    705                 break
    706 
    707         return stopped
    708 
    709     def PlaySoundOnItem(self, soundID, itemID, emitterName = '3d_sfx', maxTries = 10, sleepTime = 0.5):
    710         event = GetEventFromSoundID(soundID)
    711         if event:
    712             return self.PlayEventOnItem(event, itemID, emitterName=emitterName, maxTries=maxTries, sleepTime=sleepTime)
    713         return 0
    714 
    715     def StopSoundOnItem(self, soundID, itemID):
    716         event = GetEventFromSoundID(soundID)
    717         if event:
    718             return self.StopEventOnItem(event, itemID)
    719         return False
    720 
    721     def StopSoundOnEmitter(self, soundID, emitterID, fadeOutDuration = 1000):
    722         event = GetEventFromSoundID(soundID)
    723         if event:
    724             emitter = self.manager.GetAudioEmitter(emitterID)
    725             if emitter:
    726                 return emitter.StopEvent(event, fadeOutDuration)
    727         return False
    728 
    729     def ItemSupportsAudio(self, itemID, ball = None):
    730         if not ball:
    731             ball = self.michelle.GetBallAndWaitForModel(itemID)
    732         if ball:
    733             if self.BallSupportsAudio(ball):
    734                 return True
    735         return False
    736 
    737     def BallSupportsAudio(self, ball):
    738         model = ball.GetModel()
    739         if model:
    740             if hasattr(model, 'observers'):
    741                 return True
    742         return False
    743 
    744     def GetAudioEmittersOnItem(self, itemID):
    745         audioEmitters = []
    746         ball = self.michelle.GetBallAndWaitForModel(itemID)
    747         if ball:
    748             model = ball.GetModel()
    749             if model:
    750                 audioEmitters = model.Find('audio2.AudEmitter')
    751         return audioEmitters
    752 
    753     def SetGameParameterOnAudioEmitter(self, emitterID, parameterName, parameterValue):
    754         emitter = self.manager.GetAudioEmitter(emitterID)
    755         if emitter:
    756             emitter.SetRTPC(parameterName, parameterValue)
    757             return True
    758         return False
    759 
    760     def SetDebugLogCallback(self, callback):
    761         self.manager.SetDebugLogCallback(callback)
    762 
    763     def StopDebugLogging(self):
    764         self.manager.StopDebugLogging()
    765 
    766     def EnableDebugShowAllEmitters(self):
    767         self.manager.manager.EnableDebugDisplayAllEmitters()
    768 
    769     def DisableDebugShowAllEmitters(self):
    770         self.manager.manager.DisableDebugDisplayAllEmitters()
    771 
    772     def GetDebugDisplayAllEmitters(self):
    773         try:
    774             return self.manager.manager.GetDebugDisplayAllEmitters()
    775         except AttributeError:
    776             return False
    777 
    778     def _SetControllerVariableOnShip(self, variableName, variableValue, ball = None, shipID = 0):
    779         if not shipID:
    780             shipID = session.shipid
    781         if shipID:
    782             if not ball:
    783                 ball = self.michelle.GetBallAndWaitForModel(shipID)
    784             if ball and hasattr(ball, 'SetControllerVariable'):
    785                 ball.SetControllerVariable(variableName, variableValue)
    786 
    787     def _LimitEnginesIfNeeded(self):
    788         if self.numEntitiesInPark > audConst.ENGINE_LIMIT_MIN:
    789             if not self.engineLimit > 0:
    790                 logger.debug('Engine audio voice limiting activated.'.format(audConst.ENGINE_LIMIT_MIN))
    791             oneFifth = audConst.ENGINE_LIMIT_MIN / 5 % 100
    792             newLimit = 0
    793             if self.numEntitiesInPark in range(audConst.ENGINE_LIMIT_MIN, int(audConst.ENGINE_LIMIT_MAX * 0.5)):
    794                 newLimit = oneFifth * 4 % 100
    795             elif self.numEntitiesInPark in range(int(audConst.ENGINE_LIMIT_MAX * 0.5), int(audConst.ENGINE_LIMIT_MAX * 0.75)):
    796                 newLimit = oneFifth * 3 % 100
    797             elif self.numEntitiesInPark in range(int(audConst.ENGINE_LIMIT_MAX * 0.75), audConst.ENGINE_LIMIT_MAX):
    798                 newLimit = oneFifth * 2 % 100
    799             elif self.numEntitiesInPark > audConst.ENGINE_LIMIT_MAX:
    800                 newLimit = oneFifth
    801             if self.engineLimit != newLimit:
    802                 self.engineLimit = newLimit
    803                 self.SetGlobalRTPC(audConst.ENGINE_LIMIT_RTPC, newLimit)
    804                 logger.debug('Engine audio voice limit is {} ships at one time because there are {} entities in the park'.format(newLimit, self.numEntitiesInPark))
    805         elif self.numEntitiesInPark < audConst.ENGINE_LIMIT_MIN and self.engineLimit > 0:
    806             logger.debug('Engine audio voice limiting deactivated. There are less than {} entities in the park'.format(audConst.ENGINE_LIMIT_MIN))
    807             self.engineLimit = 0
    808             self.SetGlobalRTPC(audConst.ENGINE_LIMIT_RTPC, audConst.ENGINE_LIMIT_MIN)
    809 
    810     def _GetAndWaitForBall(self, itemID, maxTries = 10, sleepTime = 0.5):
    811         ball = None
    812         sleepCount = 0
    813         while not ball:
    814             if sleepCount > maxTries:
    815                 break
    816             ball = self.michelle.GetBall(itemID)
    817             if not ball:
    818                 sleepCount += 1
    819                 uthread2.Sleep(sleepTime)
    820 
    821         return ball
    822 
    823     def _GetOrCreateAudioEmitterForBall(self, ball, emitterName = 'entity_sfx'):
    824         audioEmitter = None
    825         if ball:
    826             if self.BallSupportsAudio(ball):
    827                 model = ball.GetModel()
    828                 emitter = model.Find('audio2.AudEmitter')
    829                 if emitter:
    830                     audioEmitter = emitter[0]
    831                     logger.info('Found existing audio emitter {} for ball {}.'.format(audioEmitter.name, ball.id))
    832                 else:
    833                     newObserver = CreateAudioObserver(emitterName)
    834                     model.observers.append(newObserver)
    835                     audioEmitter = newObserver.observer
    836                     logger.info('Created new audio emitter {} for ball {}'.format(audioEmitter.name, ball.id))
    837         return audioEmitter
    838 
    839     def GetOrCreateAudioEmitterForItem(self, itemID, emitterName = 'entity_sfx', ball = None):
    840         if not ball:
    841             ball = self.michelle.GetBallAndWaitForModel(itemID)
    842         audioEmitter = None
    843         if self.ItemSupportsAudio(itemID, ball=ball):
    844             audioEmitter = self._GetOrCreateAudioEmitterForBall(ball, emitterName=emitterName)
    845         return audioEmitter
    846 
    847     def SeekOnEventPercent(self, playingID, percentToSeek):
    848         self.uiAudioManager.SeekOnEventPercent(playingID, percentToSeek)
    849 
    850     def SeekOnEventMs(self, playingID, msToSeek):
    851         self.uiAudioManager.SeekOnEventMs(playingID, msToSeek)
    852 
    853     def GetDialoguePlayPosition(self, playingID):
    854         return self.uiAudioManager.GetEventPlayPosition(playingID)
    855 
    856     def CreateImmersiveOverlay(self, name):
    857         return self.immersiveOverlayManager.create(name)
    858 
    859     def DisableSpatialAudio(self):
    860         self.manager.DisableSpatialAudio()
    861 
    862     def EnableSpatialAudio(self):
    863         self.manager.EnableSpatialAudio()
    864 
    865     def SpatialAudioEnabled(self):
    866         return self.manager.GetSpatialAudioEnabled()
    867 
    868     def SpatialAudioIsSupported(self):
    869         if self.manager.SpatialAudioIsSupported():
    870             if self.manager.audioEndpointActive:
    871                 return True
    872         return False
    873 
    874     def UserAudioDeviceChangeCallback(self, spatialAudioSupported):
    875         self.manager.audioEndpointActive = spatialAudioSupported
    876         sm.ScatterEvent('OnUserAudioDeviceChanged')