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