1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <math.h>
6
7 #include "../include/string.h"
8 #include "../include/disk.h"
9
10 #include "sound.h"
11 #include "menu.h"
12 #include "obj.h"
13 #include "objutils.h"
14 #include "sar.h"
15 #include "sarmusic.h"
16 #include "sarmenucodes.h"
17 #include "config.h"
18
19
20 void SARMusicUpdate(sar_core_struct *core_ptr);
21
22
23 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
24 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
25 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
26
27
28 /*
29 * Checks the current situation (current music, current menu or
30 * simulation, player object state, etc) and changes the music
31 * as needed.
32 *
33 * This function should be called once per loop or whenever the
34 * music is suspected to need to be changed.
35 *
36 * The global opt->music state will be checked and music will
37 * be turned on or off as needed.
38 */
SARMusicUpdate(sar_core_struct * core_ptr)39 void SARMusicUpdate(sar_core_struct *core_ptr)
40 {
41 int prev_id, new_id, new_enter_id;
42 sar_menu_struct *cur_menu_ptr;
43 snd_recorder_struct *recorder = core_ptr->recorder;
44 sar_option_struct *opt = &core_ptr->option;
45 if(recorder == NULL)
46 return;
47
48 /* Get current music id (can be -1) and record it as the
49 * previous music id
50 */
51 prev_id = core_ptr->cur_music_id;
52
53 /* Is music state switched on in the options? */
54 if(opt->music)
55 {
56
57 }
58 else
59 {
60 /* Music is suppose to be off, so turn it off as needed
61 * and return
62 */
63 if(SoundMusicIsPlaying(recorder))
64 SoundMusicStopPlay(recorder);
65 return;
66 }
67
68 /* ******************************************************** */
69
70 /* Begin checking which music id should be played, for
71 * `repeating' and `enter' styles. After this check, new_id
72 * and new_enter_id will be updated to the id codes of the
73 * songs intended to be played
74 */
75 new_id = -1;
76 new_enter_id = -1;
77
78 /* First determine if we are in the menu system or in
79 * simulation
80 *
81 * The appropriate new music ids should be choosen (if any)
82 * here
83 */
84 cur_menu_ptr = SARGetCurrentMenuPtr(core_ptr);
85 if(cur_menu_ptr != NULL)
86 {
87 /* In menu system, choose new music ids by checking
88 * which menu we are currently in (check the current
89 * menu's name)
90 */
91 const char *menu_name = (const char *)cur_menu_ptr->name;
92 if(menu_name != NULL)
93 {
94 /* Loading simulation menu? */
95 if(!strcasecmp(menu_name, SAR_MENU_NAME_LOADING_SIMULATION))
96 {
97 new_id = SAR_MUSIC_ID_LOADING_SIMULATION;
98 }
99 /* Main menu? */
100 else if(!strcasecmp(menu_name, SAR_MENU_NAME_MAIN))
101 {
102 new_id = SAR_MUSIC_ID_MENUS;
103 }
104 /* TODO Add code to check other menus here */
105 else
106 {
107 /* Some other menu, use the generic menu music id */
108 new_id = SAR_MUSIC_ID_MENUS;
109 }
110 }
111 else
112 {
113 /* No menu name available, just use the generic menu
114 * music id then
115 */
116 new_id = SAR_MUSIC_ID_MENUS;
117 }
118 } /* In menu system? */
119 else
120 {
121 /* Not in menu system, probably in simulation. Check
122 * the state of the scene and player object to choose
123 * the appropriate music id
124 */
125 sar_scene_struct *scene = core_ptr->scene;
126 sar_object_struct *obj_ptr = NULL;
127
128
129 /* Scene structure must be available */
130 if(scene != NULL)
131 {
132 /* Get the pointer to the player object, the state
133 * of the player object will dictate which music
134 * id will be choosen.
135 */
136 obj_ptr = scene->player_obj_ptr;
137
138 /* Player object exists? */
139 if(obj_ptr != NULL)
140 {
141 sar_object_aircraft_struct *obj_aircraft_ptr;
142 sar_obj_hoist_struct *hoist_ptr;
143
144
145 /* Get pointers to object's substructures */
146 obj_aircraft_ptr = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
147 hoist_ptr = SARObjGetHoistPtr(obj_ptr, 0, NULL);
148
149 /* Begin checking by player object type and its
150 * status to determine the new music id's
151 */
152 if(obj_aircraft_ptr != NULL)
153 {
154 if(obj_aircraft_ptr->landed)
155 {
156 new_id =
157 SAR_MUSIC_ID_SIMULATION_ONGROUND;
158 new_enter_id =
159 SAR_MUSIC_ID_SIMULATION_ONGROUND_ENTER;
160 }
161 else
162 {
163 /* In flight */
164 switch(scene->tod_code)
165 {
166 case SAR_TOD_CODE_NIGHT:
167 new_id =
168 SAR_MUSIC_ID_SIMULATION_INFLIGHT_NIGHT;
169 new_enter_id =
170 SAR_MUSIC_ID_SIMULATION_INFLIGHT_NIGHT_ENTER;
171 break;
172 case SAR_TOD_CODE_DUSK:
173 case SAR_TOD_CODE_DAWN:
174 case SAR_TOD_CODE_DAY:
175 case SAR_TOD_CODE_UNDEFINED:
176 new_id =
177 SAR_MUSIC_ID_SIMULATION_INFLIGHT_DAY;
178 new_enter_id =
179 SAR_MUSIC_ID_SIMULATION_INFLIGHT_DAY_ENTER;
180 break;
181 }
182 }
183 }
184 if(hoist_ptr != NULL)
185 {
186 if(hoist_ptr->rope_cur > 0.0)
187 {
188 new_id =
189 SAR_MUSIC_ID_SIMULATION_RESCUE;
190 new_enter_id =
191 SAR_MUSIC_ID_SIMULATION_RESCUE_ENTER;
192 }
193 }
194
195 /* Set music id's to defaults if they were not able
196 * to be determined above.
197 */
198 if(new_id < 0)
199 new_id = SAR_MUSIC_ID_SIMULATION_ONGROUND;
200 if(new_enter_id < 0)
201 new_enter_id = SAR_MUSIC_ID_SIMULATION_ONGROUND_ENTER;
202 }
203 else
204 {
205 /* No player object available, assume on ground */
206 new_id = SAR_MUSIC_ID_SIMULATION_ONGROUND;
207 new_enter_id = SAR_MUSIC_ID_SIMULATION_ONGROUND_ENTER;
208 }
209 }
210
211 } /* In simulation */
212
213
214 /* ******************************************************** */
215
216 /* At this point the new music id's should have been
217 * choosen, they can still be -1 to indicate no change.
218 */
219
220 /* Macro to return the music reference file as tmp_path from the
221 * given music_ref_ptr. Uses variables tmp_path[PATH_MAX + NAME_MAX]
222 * and music_ref_ptr.
223 */
224 #define GET_MUSIC_REF_FILE \
225 { \
226 *tmp_path = '\0'; \
227 if((music_ref_ptr != NULL) ? (music_ref_ptr->filename != NULL) : 0) \
228 { \
229 struct stat stat_buf; \
230 const char *cstrptr = PrefixPaths( \
231 dname.local_data, music_ref_ptr->filename \
232 ); \
233 /* Check local file to see if it exists first */ \
234 if((cstrptr != NULL) ? !stat(cstrptr, &stat_buf) : 0) \
235 { \
236 /* Found local file, put that path value in tmp_path */ \
237 strncpy(tmp_path, cstrptr, PATH_MAX + NAME_MAX); \
238 } \
239 else \
240 { \
241 /* Check global file */ \
242 cstrptr = PrefixPaths( \
243 dname.global_data, music_ref_ptr->filename \
244 ); \
245 if((cstrptr != NULL) ? !stat(cstrptr, &stat_buf) : 0) \
246 { \
247 /* Found global file, put that path value in tmp_path */ \
248 strncpy(tmp_path, cstrptr, PATH_MAX + NAME_MAX); \
249 } \
250 } \
251 } \
252 }
253
254
255 /* Change in music id's and new music id is valid? */
256 if((new_id != prev_id) && (new_id > -1))
257 {
258 int music_ref_num;
259 sar_music_ref_struct *music_ref_ptr;
260 char tmp_path[PATH_MAX + NAME_MAX];
261
262
263 if(opt->runtime_debug)
264 printf(
265 "SARMusicUpdate(): Changing to music id %i from id %i\n",
266 new_id, prev_id
267 );
268
269 /* Find music reference in list that matches the music id
270 * specified by new_id.
271 */
272 music_ref_ptr = SARMusicMatchPtr(
273 core_ptr->music_ref, core_ptr->total_music_refs,
274 new_id, &music_ref_num
275 );
276 /* Found music reference matching new_id? */
277 if(music_ref_ptr != NULL)
278 {
279 /* Stop playing previous music (if any) and start
280 * playing the new one.
281 */
282 GET_MUSIC_REF_FILE
283 if(SoundMusicStartPlay(
284 recorder,
285 tmp_path,
286 (music_ref_ptr->flags & SAR_MUSIC_REF_FLAGS_REPEAT) ?
287 -1 : 1
288 ))
289 {
290 /* Error playing this music, need to print warning
291 * and switch off music.
292 */
293 fprintf(
294 stderr,
295 "%s: Unable to play music, turning music off.\n",
296 music_ref_ptr->filename
297 );
298 opt->music = False;
299 core_ptr->cur_music_id = prev_id = new_id = -1;
300 }
301 else
302 {
303 /* Successfully started playing new music, update
304 * current music id.
305 */
306 core_ptr->cur_music_id = prev_id = new_id;
307 }
308 }
309 else
310 {
311 /* No music reference for the given id, continue playing
312 * previous music and do not update current music id.
313 */
314 }
315 }
316 /* No change in music id's and new music id is valid? */
317 else if(new_id > -1)
318 {
319 /* No change in music id, but need to check if music is
320 * still playing. If it not playing then it needs to be
321 * either restarted or changed to the next consecutive
322 * song.
323 */
324 if(!SoundMusicIsPlaying(recorder))
325 {
326 int music_ref_num;
327 sar_music_ref_struct *music_ref_ptr;
328 char tmp_path[PATH_MAX + NAME_MAX];
329
330
331 if(opt->runtime_debug)
332 printf(
333 "SARMusicUpdate(): Music id %i has stopped playing.\n",
334 new_id
335 );
336
337 /* Update new_id to the `next' song that needs to be
338 * played after the current one has stopped.
339 */
340 switch(prev_id)
341 {
342 case SAR_MUSIC_ID_SIMULATION_ONGROUND_ENTER:
343 new_id = SAR_MUSIC_ID_SIMULATION_ONGROUND;
344 break;
345
346 case SAR_MUSIC_ID_SIMULATION_INFLIGHT_DAY_ENTER:
347 new_id = SAR_MUSIC_ID_SIMULATION_INFLIGHT_DAY;
348 break;
349
350 case SAR_MUSIC_ID_SIMULATION_INFLIGHT_NIGHT_ENTER:
351 new_id = SAR_MUSIC_ID_SIMULATION_INFLIGHT_NIGHT;
352 break;
353
354 case SAR_MUSIC_ID_SIMULATION_RESCUE_ENTER:
355 new_id = SAR_MUSIC_ID_SIMULATION_RESCUE;
356 break;
357
358 default:
359 /* All other music id's when stopped should just
360 * re-start as the same music id.
361 */
362 new_id = prev_id;
363 break;
364 }
365
366 if(opt->runtime_debug)
367 printf(
368 "SARMusicUpdate(): Previous music id %i stopped, playing new music id %i.\n",
369 prev_id, new_id
370 );
371
372 /* Find music reference in list that matches the music
373 * id specified by new_id.
374 */
375 music_ref_ptr = SARMusicMatchPtr(
376 core_ptr->music_ref, core_ptr->total_music_refs,
377 new_id, &music_ref_num
378 );
379 /* Found music reference matching new_id? */
380 if(music_ref_ptr != NULL)
381 {
382 /* Start playing new music */
383 GET_MUSIC_REF_FILE
384 if(SoundMusicStartPlay(
385 recorder,
386 tmp_path,
387 (music_ref_ptr->flags & SAR_MUSIC_REF_FLAGS_REPEAT) ?
388 -1 : 1
389 ))
390 {
391 /* Error playing this music, need to print warning
392 * and switch off music.
393 */
394 fprintf(
395 stderr,
396 "%s: Unable to play music, turning music off.\n",
397 music_ref_ptr->filename
398 );
399 opt->music = False;
400 core_ptr->cur_music_id = prev_id = new_id = -1;
401 }
402 else
403 {
404 /* Successfully started playing new music, update
405 * current music id.
406 */
407 core_ptr->cur_music_id = prev_id = new_id;
408 }
409 }
410 else
411 {
412 /* No music reference for the given id or music needs
413 * to stop until changed. So do not update the current
414 * music id (even if the previous music has stopped).
415 */
416 }
417 } /* Music has stopped playing? */
418 }
419
420 #undef GET_MUSIC_REF_FILE
421 }
422
423