source: src/mlx/soundsched.py@ 170:7cda0cc74e19

Last change on this file since 170:7cda0cc74e19 was 170:7cda0cc74e19, checked in by István Váradi <ivaradi@…>, 12 years ago

The background sounds play back properly

File size: 8.1 KB
Line 
1# Module to schedule the sounds to be played
2
3#------------------------------------------------------------------------------
4
5from sound import startSound
6import const
7
8import threading
9
10#------------------------------------------------------------------------------
11
12class Sound(object):
13 """A sound (file) that should be played in certain circumstances."""
14
15 # Common lock for sounds
16 _lock = threading.Lock()
17
18 def __init__(self, name):
19 """Construct the sound object for the sound file with the given
20 name."""
21 self._name = name
22
23 self._playing = 0
24
25 @property
26 def playing(self):
27 """Determine if sound is playing or not."""
28 return self._playing>0
29
30 def check(self, flight, state, pilotHotkeyPressed):
31 """Check if the file should be played, and if it should be, play it."""
32 if self.shouldPlay(flight, state, pilotHotkeyPressed):
33 with Sound._lock:
34 self._playing += 1
35 startSound(self._name, finishCallback = self._playbackDone)
36
37 def shouldPlay(self, flight, state, pilotHotkeyPressed):
38 """Determine if the sound should be played.
39
40 This default implementation returns False."""
41 return False
42
43 def _playbackDone(self, success, extra):
44 """Called when the playback of thee sound has finished (or failed)."""
45 if success is None:
46 print "Failed to start sound", self._name
47 elif not success:
48 print "Failed to finish sound", self._name
49 with Sound._lock:
50 self._playing -= 1
51
52#------------------------------------------------------------------------------
53
54class ScreamSound(Sound):
55 """A screaming sound that is played under certain circumstance."""
56 def __init__(self):
57 """Construct the screaming sound."""
58 super(ScreamSound, self).__init__(const.SOUND_SCREAM)
59
60 def shouldPlay(self, flight, state, pilotHotkeyPressed):
61 """Determine if the sound should be played.
62
63 It should be played if it is not being played and the absolute value of
64 the vertical speed is greater than 6000 fpm."""
65 return not self.playing and abs(state.vs)>6000
66
67#------------------------------------------------------------------------------
68
69class SimpleSound(Sound):
70 """A simple sound that should be played only once, in a certain flight
71 stage when the hotkey has been pressed or it is not the pilot who controls
72 the sounds.
73
74 If it is not the pilot who controls the sounds, it may be delayed relative
75 to the first detection of a certain flight stage."""
76 def __init__(self, name, stage, delay = 0.0, extraCondition = None,
77 considerHotkey = True, previousSound = None):
78 """Construct the simple sound."""
79 super(SimpleSound, self).__init__(name)
80
81 self._stage = stage
82 self._delay = delay
83 self._extraCondition = extraCondition
84 self._considerHotkey = considerHotkey
85 self._previousSound = previousSound
86
87 self._played = False
88 self._stageDetectionTime = None
89
90 def shouldPlay(self, flight, state, pilotHotkeyPressed):
91 """Determine if the sound should be played."""
92 if flight.stage!=self._stage or self._played or \
93 (self._previousSound is not None and
94 self._previousSound.playing):
95 return False
96
97 toPlay = False
98 if flight.config.pilotControlsSounds and self._considerHotkey:
99 toPlay = pilotHotkeyPressed
100 else:
101 if self._stageDetectionTime is None:
102 self._stageDetectionTime = state.timestamp
103 toPlay = state.timestamp>=(self._stageDetectionTime + self._delay)
104 if toPlay and self._extraCondition is not None:
105 toPlay = self._extraCondition(flight, state)
106
107 if toPlay:
108 self._played = True
109
110 return toPlay
111
112#------------------------------------------------------------------------------
113
114class TaxiSound(SimpleSound):
115 """The taxi sound.
116
117 It first plays the Malev theme song, then an aircraft-specific taxi
118 sound. The playback is started only, if the boarding sound is not being
119 played."""
120
121 _sounds = { const.AIRCRAFT_B736 : const.SOUND_TAXI_BOEING737NG,
122 const.AIRCRAFT_B737 : const.SOUND_TAXI_BOEING737NG,
123 const.AIRCRAFT_B738 : const.SOUND_TAXI_BOEING737NG,
124 const.AIRCRAFT_B762 : const.SOUND_TAXI_BOEING767,
125 const.AIRCRAFT_B763 : const.SOUND_TAXI_BOEING767,
126 const.AIRCRAFT_F70 : const.SOUND_TAXI_F70 }
127
128 def __init__(self, flight, boardingSound = None):
129 """Construct the taxi sound."""
130 super(TaxiSound, self).__init__(const.SOUND_MALEV,
131 const.STAGE_PUSHANDTAXI,
132 previousSound = boardingSound,
133 extraCondition = lambda _flight, state:
134 state.groundSpeed>5)
135
136 self._flight = flight
137
138 def _playbackDone(self, success, extra):
139 """Called when the playback is done.
140
141 It starts playing the aircraft type-specific taxi sound, if any."""
142 super(TaxiSound, self)._playbackDone(success, extra)
143 aircraftType = self._flight.aircraftType
144 sounds = TaxiSound._sounds
145 if aircraftType in sounds:
146 startSound(sounds[aircraftType])
147
148#------------------------------------------------------------------------------
149
150class TouchdownApplause(Sound):
151 """An applause sound that is played after a gentle touchdown."""
152 def __init__(self):
153 super(TouchdownApplause, self).__init__(const.SOUND_APPLAUSE)
154
155 self._touchdownTime = None
156 self._played = False
157
158 def shouldPlay(self, flight, state, pilotHotkeyPressed):
159 """Determine if the sound should be played.
160
161 It should be played if we are 2 seconds after a gentle touchdown."""
162 if self._played or flight.tdRate is None:
163 return False
164
165 if self._touchdownTime is None:
166 self._touchdownTime = state.timestamp
167
168 if state.timestamp>=(self._touchdownTime + 2) and \
169 flight.tdRate<150:
170 self._played = True
171 return True
172 else:
173 return False
174
175#------------------------------------------------------------------------------
176
177class SoundScheduler(object):
178 """A scheduler for the sounds."""
179 def __init__(self, flight):
180 """Construct the sound scheduler for the given flight."""
181 self._flight = flight
182 self._sounds = []
183
184 self._sounds.append(ScreamSound())
185
186 boardingSound = SimpleSound(const.SOUND_BOARDING,
187 const.STAGE_BOARDING,
188 delay = 10.0)
189 self._sounds.append(boardingSound)
190 self._sounds.append(TaxiSound(flight, boardingSound))
191 self._sounds.append(SimpleSound(const.SOUND_CAPTAIN_TAKEOFF,
192 const.STAGE_TAKEOFF,
193 extraCondition = lambda flight, state:
194 state.landingLightsOn or state.gs>80,
195 considerHotkey = False))
196 self._sounds.append(SimpleSound(const.SOUND_CRUISE, const.STAGE_CRUISE))
197 self._sounds.append(SimpleSound(const.SOUND_DESCENT, const.STAGE_DESCENT,
198 extraCondition = lambda flight, state:
199 state.altitude<15000))
200 self._sounds.append(TouchdownApplause())
201 self._sounds.append(SimpleSound(const.SOUND_TAXIAFTERLAND,
202 const.STAGE_TAXIAFTERLAND,
203 delay = 10.0))
204
205 def schedule(self, state, pilotHotkeyPressed):
206 """Schedule any sound, if needed."""
207 flight = self._flight
208 if flight.config.enableSounds:
209 for sound in self._sounds:
210 sound.check(flight, state, pilotHotkeyPressed)
211
212#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.