source: src/mlx/soundsched.py@ 222:08d0fc465f9d

Last change on this file since 222:08d0fc465f9d was 208:22ff615383e9, checked in by István Váradi <ivaradi@…>, 12 years ago

It is now possible to cancel a flight and to start a new one at the end and also to refresh the list of flights.

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