1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * $Source: r:/prj/cit/src/RCS/musicai.c $
21  * $Revision: 1.124 $
22  * $Author: unknown $
23  * $Date: 1994/11/26 03:16:18 $
24  */
25 
26 #define __MUSICAI_SRC
27 
28 #include <string.h>
29 #include <stdlib.h>
30 
31 #include "Shock.h"
32 #include "Prefs.h"
33 
34 #include "musicai.h"
35 #include "MacTune.h"
36 
37 #include "ai.h"
38 #include "faketime.h"
39 #include "map.h"
40 #include "mapflags.h"
41 #include "player.h"
42 #include "sfxlist.h"
43 #include "tickcount.h"
44 #include "tools.h"
45 
46 #include "adlmidi.h"
47 #include "Xmi.h"
48 
49 /*
50 #include <mainloop.h>
51 #include <_audio.h>
52 #include <_testing.h>
53 #include <objects.h>
54 #include <objcrit.h>
55 #include <texttool.h>
56 #include <otrip.h>
57 #include <diginode.h>
58 */
59 #ifdef AUDIOLOGS
60 #include "audiolog.h"
61 #endif
62 
63 //#include <ail.h>
64 
65 extern void grind_music_ai();
66 
67 uchar music_card = TRUE, music_on = FALSE;
68 
69 uchar track_table[NUM_SCORES][SUPERCHUNKS_PER_SCORE];
70 uchar transition_table[NUM_TRANSITIONS];
71 uchar layering_table[NUM_LAYERS][MAX_KEYS];
72 uchar key_table[NUM_LAYERABLE_SUPERCHUNKS][KEY_BAR_RESOLUTION];
73 
74 char peril_bars = 0;
75 
76 int new_theme = 0;
77 int new_x, new_y;
78 int old_bore;
79 short mai_override = 0;
80 uchar cyber_play = 255;
81 
82 int layer_danger = 0;
83 int layer_success = 0;
84 int layer_transition = 0;
85 int transition_count = 0;
86 char tmode_time = 0;
87 int actual_score = 0;
88 uchar decon_count = 0;
89 uchar decon_time = 8;
90 uchar in_deconst = FALSE, old_deconst = FALSE;
91 uchar in_peril = FALSE;
92 uchar just_started = TRUE;
93 int score_playing = 0;
94 short curr_ramp_time, curr_ramp;
95 char curr_prioritize, curr_crossfade;
96 
97 void musicai_clear();
98 errtype mai_transition(int new_trans);
99 
100 extern errtype make_request(int chunk_num, int piece_ID);
101 extern int digifx_volume_shift(short x, short y, short z, short phi, short theta, short basevol);
102 extern int digifx_pan_shift(short x, short y, short z, short phi, short theta);
103 extern uchar mai_semaphor;
104 
105 uchar park_random = 75;
106 uchar park_playing = 0;
107 uchar access_random = 45;
108 
109 ulong last_damage_sum = 0;
110 ulong last_vel_time = 0;
111 
112 // Damage taken decay & quantity of decay
113 int danger_hp_level = 10;
114 int danger_damage_level = 40;
115 int damage_decay_time = 300;
116 int damage_decay_amount = 6;
117 int mai_damage_sum = 0;
118 
119 // How long an attack keeps us in combat music mode
120 int mai_combat_length = 1000;
121 
122 uchar bad_digifx = FALSE;
123 
124 // KLC - no longer need this   Datapath music_dpath;
125 
126 #define SMALL_ROBOT_LAYER 3
127 
128 char mlimbs_machine = 0;
129 
130 //------------------
131 //  INTERNAL PROTOTYPES
132 //------------------
133 errtype musicai_shutdown();
134 errtype musicai_reset(uchar runai);
135 int gen_monster(int monster_num);
136 
musicai_shutdown()137 errtype musicai_shutdown() {
138     int i;
139     for (i = 0; i < MLIMBS_MAX_SEQUENCES - 1; i++)
140         current_request[i].pieceID = 255;
141     MacTuneKillCurrentTheme();
142     return (OK);
143 }
144 
145 extern uchar run_asynch_music_ai;
146 
musicai_reset(uchar runai)147 errtype musicai_reset(uchar runai) {
148     if (runai) // Figure out if there is a theme to start with.
149         grind_music_ai();
150     mlimbs_counter = 0;
151     return (OK);
152 }
153 
musicai_clear()154 void musicai_clear() {
155     mai_damage_sum = 0;
156     last_damage_sum = 0;
157     mlimbs_combat = 0;
158 }
159 
mlimbs_do_ai()160 void mlimbs_do_ai() {
161     //   extern uchar mlimbs_semaphore;
162     extern errtype check_asynch_ai(uchar new_score_ok);
163     extern ObjID damage_sound_id;
164     extern char damage_sound_fx;
165 
166     if (!IsPlaying(0)) gReadyToQueue = 1;
167 
168 
169     //repeat shorter tracks while thread 0 is still playing
170     if (!gReadyToQueue)
171     {
172         for (int i = 1; i < MLIMBS_MAX_CHANNELS - 1; i++)
173             if (current_request[i].pieceID != 255)
174                 if (!IsPlaying(i))
175                 {
176                     make_request(i, current_request[i].pieceID);
177                     current_request[i].pieceID = 255; //make sure it only plays this time
178                 }
179     }
180 
181 
182     /* Is this really necessary?  It's already called twice in fr_rend().
183     #ifdef AUDIOLOGS
184             audiolog_loop_callback();
185     #endif
186     */
187     // Play any queued sound effects, or damage SFX that have yet to get flushed
188     if (damage_sound_fx != -1) {
189         play_digi_fx_obj(damage_sound_fx, 1, damage_sound_id);
190         damage_sound_fx = -1;
191     }
192 
193     if (music_on) {
194         if (mlimbs_combat != 0) {
195             if (mlimbs_combat < player_struct.game_time)
196                 mlimbs_combat = 0;
197         }
198 
199         // Set danger layer
200         layer_danger = 0;
201         if (mai_damage_sum > danger_damage_level)
202             layer_danger = 2;
203         else if (player_struct.hit_points < danger_hp_level)
204             layer_danger = 1;
205 
206         // Decay damage
207         if ((last_damage_sum + damage_decay_time) < player_struct.game_time) {
208             mai_damage_sum -= damage_decay_amount;
209             if (mai_damage_sum < 0)
210                 mai_damage_sum = 0;
211             last_damage_sum = player_struct.game_time;
212         }
213 
214         if ((score_playing == BRIDGE_ZONE) && in_peril) {
215             mlimbs_peril = DEFAULT_PERIL_MIN;
216             mlimbs_combat = 0;
217         } else {
218             if ((mlimbs_combat > 0) || in_peril) {
219                 mlimbs_peril = DEFAULT_PERIL_MAX;
220             }
221         }
222 
223         // KLC - moved here from grind_music_ai, so it can do this check at all times.
224         if (global_fullmap->cyber) {
225             MapElem *pme;
226             int play_me;
227 
228             pme = MAP_GET_XY(PLAYER_BIN_X, PLAYER_BIN_Y); // Determine music for this
229             if (!me_bits_peril(pme))                      // location in cyberspace.
230                 play_me = NUM_NODE_THEMES + me_bits_music(pme);
231             else
232                 play_me = me_bits_music(pme);
233             if (play_me != cyber_play) // If music needs to be changed, then
234             {
235                 musicai_shutdown();         // stop playing current tune
236                 make_request(0, play_me);   // setup new tune
237                 musicai_reset(FALSE);       // reset MLIMBS and
238                 MacTuneStartCurrentTheme(); // start playing the new tune.
239             } else
240                 make_request(0, play_me); // otherwise just queue up next tune.
241             cyber_play = play_me;
242         }
243 
244         // This is all pretty temporary right now, but here's what's happening.
245         // If the gReadyToQueue flag is set, that means the 6-second timer has
246         // fired.  So we call check_asynch_ai() to determine the next tune to play
247         // then queue it up.
248         //  Does not handle layering.  Just one music track!
249         if (gReadyToQueue) {
250             extern bool mlimbs_update_requests;
251             mlimbs_update_requests = TRUE;
252 
253             if (!global_fullmap->cyber)
254                 check_asynch_ai(TRUE);
255             int pid = current_request[0].pieceID;
256             if (pid != 255) // If there is a theme to play,
257             {
258                 MacTuneQueueTune(pid); // Queue it up.
259                 mlimbs_counter++;      // Tell mlimbs we've queued another tune.
260                 gReadyToQueue = FALSE;
261             }
262         }
263 
264         // If a tune has finished playing, then another has just started, so prime the
265         // timer to do the next tune calc.
266         // if (gTuneDone) {
267         //    MacTunePrimeTimer();
268         //    gTuneDone = FALSE;
269         // }
270     }
271 }
272 
273 #ifdef NOT_YET //
274 
mlimbs_do_credits_ai()275 void mlimbs_do_credits_ai() {
276     extern uchar mlimbs_semaphore;
277     if (ai_cycle) {
278         ai_cycle = 0;
279         grind_credits_music_ai();
280         mlimbs_preload_requested_timbres();
281         mlimbs_semaphore = FALSE;
282     }
283 }
284 
285 #endif // NOT_YET
286 
mai_attack()287 errtype mai_attack() {
288     if (music_on) {
289         mlimbs_combat = player_struct.game_time + mai_combat_length;
290     }
291     return (OK);
292 }
293 
mai_intro()294 errtype mai_intro() {
295     if (music_on) {
296         if (transition_table[TRANS_INTRO] != 255)
297             mai_transition(TRANS_INTRO);
298         mlimbs_peril = DEFAULT_PERIL_MIN;
299         mlimbs_combat = 0;
300     }
301     return (OK);
302 }
303 
mai_monster_nearby(int monster_type)304 errtype mai_monster_nearby(int monster_type) {
305     if (music_on) {
306         mlimbs_monster = monster_type;
307         if (monster_type == NO_MONSTER) {
308             mlimbs_combat = 0;
309             mlimbs_peril = DEFAULT_PERIL_MIN;
310         }
311     }
312     return (OK);
313 }
314 
mai_monster_defeated()315 errtype mai_monster_defeated() {
316     if (music_on) {
317         mlimbs_combat = 0;
318     }
319     return (OK);
320 }
321 
mai_player_death()322 errtype mai_player_death() {
323     if (music_on) {
324         mai_transition(TRANS_DEATH);
325         mlimbs_peril = DEFAULT_PERIL_MIN;
326         peril_bars = 0;
327         layer_danger = 0;
328         mai_damage_sum = 0;
329         layer_success = 0;
330         mlimbs_machine = 0;
331         mlimbs_monster = 0;
332         mlimbs_combat = 0;
333         musicai_shutdown();
334         make_request(0, transition_table[TRANS_DEATH]);
335         musicai_reset(FALSE);
336         MacTuneStartCurrentTheme();
337     }
338     return (OK);
339 }
340 
mlimbs_AI_init(void)341 errtype mlimbs_AI_init(void) {
342     mlimbs_boredom = 0;
343     old_bore = 0;
344     mlimbs_monster = NO_MONSTER;
345     wait_flag = FALSE;
346     random_flag = 0;
347     boring_count = 0;
348     ai_cycle = 0;
349     mlimbs_peril = DEFAULT_PERIL_MAX;
350     current_transition = TRANS_INTRO;
351     current_mode = TRANSITION_MODE;
352     tmode_time = 1; // KLC - was 4
353     current_score = actual_score = last_score = WALKING_SCORE;
354     current_zone = HOSPITAL_ZONE;
355     //   mlimbs_AI = &music_ai;
356     cyber_play = 255;
357 
358     return (OK);
359 }
360 
mai_transition(int new_trans)361 errtype mai_transition(int new_trans) {
362     if ((next_mode == TRANSITION_MODE) || (current_mode == TRANSITION_MODE))
363         return (ERR_NOEFFECT);
364 
365     if (transition_table[new_trans] < LAYER_BASE) {
366         current_transition = new_trans;
367         next_mode = TRANSITION_MODE;
368         tmode_time = 1; // KLC - was 4
369     } else if ((transition_count == 0) && (layering_table[TRANSITION_LAYER_BASE + new_trans][0] != 255)) {
370         current_transition = new_trans;
371         // For now, let's not do any layered transitions.
372         //      transition_count = 1;		//KLC - was 2
373     }
374     // temp
375     /*
376     char	msg[30];
377     lg_sprintf(msg, "Transitioning:%d, mode:%d, count:%d", new_trans, next_mode, transition_count);
378     message_info(msg);
379     */
380     return (OK);
381 }
382 
gen_monster(int monster_num)383 int gen_monster(int monster_num) {
384     if (monster_num < 3)
385         return (0);
386     if (monster_num < 6)
387         return (1);
388     return (2);
389 }
390 
391 int ext_rp = -1;
392 
393 extern struct mlimbs_request_info default_request;
394 
make_request(int chunk_num,int piece_ID)395 errtype make_request(int chunk_num, int piece_ID) {
396     current_request[chunk_num] = default_request;
397     current_request[chunk_num].pieceID = piece_ID;
398 
399     // These get set all around differently and stuff
400     current_request[chunk_num].crossfade = curr_crossfade;
401     current_request[chunk_num].ramp_time = curr_ramp_time;
402     current_request[chunk_num].ramp = curr_ramp;
403 
404     DEBUG("make_request %i %i", chunk_num, piece_ID);
405 
406     extern int WonGame_ShowStats;
407 
408     int i = chunk_num;
409     int track = 1+piece_ID;
410     if (i >= 0 && i < NUM_THREADS && track >= 0 && track < NumTracks && !WonGame_ShowStats && !IsPlaying(i))
411     {
412 //        extern uchar curr_vol_lev;
413 //        int volume = (int)curr_vol_lev * 127 / 100; //convert from 0-100 to 0-127
414         StartTrack(i, track);
415     }
416 
417     return (OK);
418 }
419 
420 /*
421 errtype load_score_from_cfg(FSSpec *specPtr)
422 {
423         short  	filenum;
424         Handle	binHdl;
425         Ptr		p;
426 
427         filenum = FSpOpenResFile(specPtr, fsRdPerm);
428         if (filenum == -1)
429                 return (ERR_FOPEN);
430         binHdl = GetResource('tbin', 128);
431         if (binHdl == NULL)
432                 return (ERR_FOPEN);
433 
434         HLock(binHdl);
435         p = *binHdl;
436         BlockMoveData(p, track_table, NUM_SCORES * SUPERCHUNKS_PER_SCORE);
437         p += NUM_SCORES * SUPERCHUNKS_PER_SCORE;
438         BlockMoveData(p, transition_table, NUM_TRANSITIONS);
439         p += NUM_TRANSITIONS;
440         BlockMoveData(p, layering_table, NUM_LAYERS * MAX_KEYS);
441         p += NUM_LAYERS * MAX_KEYS;
442         BlockMoveData(p, key_table, NUM_LAYERABLE_SUPERCHUNKS * KEY_BAR_RESOLUTION);
443         HUnlock(binHdl);
444 
445         CloseResFile(filenum);
446         return(OK);
447 }
448 */
449 
450 int old_score;
451 
fade_into_location(int x,int y)452 errtype fade_into_location(int x, int y) {
453     MapElem *pme;
454 
455     new_x = x;
456     new_y = y;
457     new_theme = 2;
458     pme = MAP_GET_XY(new_x, new_y);
459     score_playing = me_bits_music(pme);
460 
461     // For going into/outof elevator and cyberspace, don't do any crossfading.
462     if ((score_playing == ELEVATOR_ZONE) || (score_playing > CYBERSPACE_SCORE_BASE) || (old_score == ELEVATOR_ZONE) ||
463         (old_score > CYBERSPACE_SCORE_BASE)) {
464         if (old_score != score_playing) // Don't restart music if going from elevator
465         {                               // to elevator (eg, when changing levels).
466             load_score_for_location(new_x, new_y);
467             MacTuneStartCurrentTheme();
468             new_theme = 0;
469         }
470     } else // for now, we're not going to do any cross-fading.  Just load the new score.
471     {
472         //		message_info("Sould be fading into new location.");
473         load_score_for_location(new_x, new_y);
474         MacTuneStartCurrentTheme();
475         new_theme = 0;
476     }
477     return (OK);
478 }
479 
480 /*KLC - don't need
481 errtype blank_theme_data()
482 {
483    LG_memset(track_table, 255, NUM_SCORES * SUPERCHUNKS_PER_SCORE * sizeof(uchar));
484    LG_memset(transition_table, 255, NUM_TRANSITIONS * sizeof(uchar));
485    LG_memset(layering_table, 255, NUM_LAYERS * MAX_KEYS * sizeof(uchar));
486    LG_memset(key_table, 255, NUM_LAYERABLE_SUPERCHUNKS * KEY_BAR_RESOLUTION * sizeof(uchar));
487    return(OK);
488 }
489 */
490 
491 // don't need?     uchar voices_4op = FALSE;
492 // don't need?     uchar digi_gain = FALSE;
load_score_guts(uint8_t score_play)493 void load_score_guts(uint8_t score_play) {
494     int rv;
495     char base[20];
496 
497     // Get the theme file name.
498     sprintf(base, "thm%d", score_play);
499     musicai_shutdown();
500 
501     // rv = MacTuneLoadTheme(&themeSpec, score_playing);
502     rv = MacTuneLoadTheme(base, score_play);
503 
504     if (rv == 0) {
505         musicai_reset(false);
506     }
507     else {
508         DEBUG("%s: load theme failed!", __FUNCTION__); // handle this a better way.
509     }
510 }
511 
load_score_for_location(int x,int y)512 errtype load_score_for_location(int x, int y) {
513     MapElem *pme;
514     char sc;
515     extern char old_bits;
516 
517     pme = MAP_GET_XY(x, y);
518     sc = me_bits_music(pme);
519     // KLC   if ((global_fullmap->cyber) && (sc != 0))
520     if (global_fullmap->cyber)
521         sc = CYBERSPACE_SCORE_BASE;
522     old_bits = old_score = score_playing = sc;
523     if (sc == 7) // Randomize boredom for the elevator
524         mlimbs_boredom = TickCount() % 8;
525     else
526         mlimbs_boredom = 0;
527     load_score_guts(sc);
528     return (OK);
529 }
530 
531 #ifdef NOT_YET //
532 
533 // 16384
534 // 8192
535 //#define SFX_BUFFER_SIZE    8192
536 #define MIDI_TYPE 0
537 #define DIGI_TYPE 1
538 // #define SPCH_TYPE   2    // perhaps someday, for special CD speech and separate SB digital effects, eh?
539 #define DEV_TYPES 2
540 
541 #define DEV_CARD 0
542 #define DEV_IRQ 1
543 #define DEV_DMA 2
544 #define DEV_IO 3
545 #define DEV_DRQ 4
546 #define DEV_PARMS 5
547 
548 // doug gets sneaky, film at 11
549 #define MIDI_CARD MIDI_TYPE][DEV_CARD
550 #define MIDI_IRQ  MIDI_TYPE][DEV_IRQ
551 #define MIDI_DMA  MIDI_TYPE][DEV_DMA
552 #define MIDI_IO   MIDI_TYPE][DEV_IO
553 #define MIDI_DRQ  MIDI_TYPE][DEV_DRQ
554 #define DIGI_CARD DIGI_TYPE][DEV_CARD
555 #define DIGI_IRQ  DIGI_TYPE][DEV_IRQ
556 #define DIGI_DMA  DIGI_TYPE][DEV_DMA
557 #define DIGI_IO   DIGI_TYPE][DEV_IO
558 #define DIGI_DRQ  DIGI_TYPE][DEV_DRQ
559 
560 #define SFX_BUFFER_SIZE 8192
561 //#define SFX_BUFFER_SIZE 4096
562 
563 static char *dev_suffix[] = {"card", "irq", "dma", "io", "drq"};
564 static char *dev_prefix[] = {"midi_", "digi_"};
565 
music_get_config(char * pre,char * suf)566 short music_get_config(char *pre, char *suf) {
567     int tmp_in, dummy_count = 1;
568     char buf[20];
569     strcpy(buf, pre);
570     strcat(buf, suf);
571     if (!config_get_value(buf, CONFIG_INT_TYPE, &tmp_in, &dummy_count))
572         return -1;
573     else
574         return (short)tmp_in;
575 }
576 
fill_audio_card(audio_card * cinf,short * dinf)577 audio_card *fill_audio_card(audio_card *cinf, short *dinf) {
578     cinf->type = dinf[DEV_CARD];
579     cinf->dname = NULL;
580     cinf->io = dinf[DEV_IO];
581     cinf->irq = dinf[DEV_IRQ];
582     cinf->dma_8bit = dinf[DEV_DMA];
583     cinf->dma_16bit = -1; // who knows, eh?
584     return cinf;
585 }
586 
587 #ifdef PLAYTEST
588 static char def_sound_path[] = "r:\\prj\\cit\\src\\sound";
589 #else
590 static char def_sound_path[] = "sound";
591 #endif
592 
593 #ifdef SECRET_SUPPORT
594 FILE *secret_fp = NULL;
595 char secret_dc_buf[10000];
596 volatile char secret_update = FALSE;
secret_closedown(void)597 void secret_closedown(void) {
598     if (secret_fp != NULL)
599         fclose(secret_fp);
600 }
601 #endif
602 
603 #endif // NOT_YET
604 
605 //----------------------------------------------------------------------
606 //  For Mac version, the vast majority of the config mess just goes away.  But we do check for
607 //  the presence of QuickTime Musical Instruments.
608 //----------------------------------------------------------------------
music_init()609 errtype music_init() {
610     /* put in later
611        int i,j;
612        uchar gm=FALSE;
613        short dev_info[DEV_TYPES][DEV_PARMS];
614        char s[64],path[64];
615        audio_card card_info;
616        extern uchar curr_sfx_vol;
617        extern char curr_vol_lev;
618 
619     #ifdef SECRET_SUPPORT
620        if ((secret_fp=fopen("secret.ddb","wt"))!=NULL)
621        {
622           secret_dc_buf[0]='\0';
623           mono_clear();
624           mono_split(MONO_AXIS_Y,4);
625           mono_setwin(2);
626        }
627        atexit(secret_closedown);
628     #endif
629 
630        strcpy(s,def_sound_path);
631 
632        dev_info[MIDI_CARD]=music_get_config(dev_prefix[0],dev_suffix[0]);
633        dev_info[DIGI_CARD]=music_get_config(dev_prefix[1],dev_suffix[0]);
634 
635        DatapathClear(&music_dpath);
636 
637        // can we make this actually know what is going on?
638        switch (dev_info[MIDI_CARD])
639        {     // probably should be in the library, not here...
640        case GRAVISULTRASTUPID: case MT32: case GENMIDI: case AWE32: case SOUNDSCAPE: case RAP_10: gm=TRUE; break;
641        }
642 
643        // add contents of CFG_SOUNDVAR
644        if (config_get_raw(CFG_SOUNDVAR,path,64))
645        {
646     //      mprintf("hey, path = %s\n",path);
647           DatapathAdd(&music_dpath, path);
648           if (gm)
649              { strcat(path,"\\genmidi"); }
650           else
651              { strcat(path,"\\sblaster"); }
652     //      mprintf("now, path = %s\n",path);
653           DatapathAdd(&music_dpath,path);
654        }
655 
656        // add contents of CFG_CD_SOUNDVAR
657        if (config_get_raw(CFG_CD_SOUNDVAR,path,64))
658        {
659     //      mprintf("hey, path = %s\n",path);
660           DatapathAdd(&music_dpath, path);
661           if (gm)
662              { strcat(path,"\\genmidi"); }
663           else
664              { strcat(path,"\\sblaster"); }
665     //      mprintf("now, path = %s\n",path);
666           DatapathAdd(&music_dpath,path);
667        }
668 
669     #ifdef PLAYTEST
670        DatapathAdd(&music_dpath,s+15); // and go back and add net/sound if necessary
671     #else
672        DatapathAdd(&music_dpath,s);
673     #endif
674 
675        if (gm)
676           { strcat(s,"\\genmidi"); }
677        else
678           { strcat(s,"\\sblaster"); }
679 
680     #ifdef PLAYTEST
681        DatapathAdd(&music_dpath,s+15);        // add just sound/devtype
682        DatapathAdd(&music_dpath,s);
683        s[21] = '\0';
684        DatapathAdd(&music_dpath,s);
685     #else
686        DatapathAdd(&music_dpath,s);        // add just sound/devtype
687     #endif
688 
689        snd_setup(&music_dpath,"sound/cit");      // really it should go find cit.ad on the datapath, then use its path
690 
691        music_card=(dev_info[MIDI_CARD]>0);
692        sfx_card  =(dev_info[DIGI_CARD]>0);
693        if (!(music_card||sfx_card))
694        {
695           curr_sfx_vol = 0;
696           curr_vol_lev = 0;
697                return(ERR_NODEV);
698        }
699 
700        for (i=0; i<DEV_TYPES; i++)
701           if (dev_info[i][DEV_CARD]!=-1)
702                   for (j=1; j<DEV_PARMS; j++)
703                 dev_info[i][j]=music_get_config(dev_prefix[i],dev_suffix[j]);
704 
705     #define ULTRA_GROSS_JOHN_MILES_HACK
706     #ifdef ULTRA_GROSS_JOHN_MILES_HACK
707        {
708           #include <conio.h>
709           if ((dev_info[MIDI_CARD]==GENMIDI)&&(dev_info[DIGI_CARD]==SOUNDBLASTERPRO2)) {
710              int mod_loc=dev_info[DIGI_IO];      // loc, the io port to send too
711              if (mod_loc==-1) mod_loc=0x220;     // i know much secretness of destruction
712              outp(mod_loc+4,0x83);     // such that def io is 220, which AIL wont
713              outp(mod_loc+5,0xb);	   // tell me till later, when we init it
714           }                                      // which we are not allowed to do yet
715        }
716     #endif
717 
718        if (music_card)
719        {
720           if (snd_start_midi(fill_audio_card(&card_info,dev_info[MIDI_TYPE]))!=SND_OK)
721           {
722              Warning(("Device %d not loaded for Midi at %x %x %x
723     %x\n",dev_info[MIDI_CARD],dev_info[MIDI_IO],dev_info[MIDI_IRQ],dev_info[MIDI_DMA],dev_info[MIDI_DRQ])); music_card =
724     FALSE; curr_vol_lev = 0;
725           }
726           else
727           {
728              mlimbs_init();
729           }
730        }
731        else
732           curr_vol_lev = 0;
733 
734        if (sfx_card)
735        {
736           if (snd_start_digital(fill_audio_card(&card_info,dev_info[DIGI_TYPE]))!=SND_OK)
737                {
738                   Warning(("Device %d not loaded for DigiFx at %x %x %x
739     %x\n",dev_info[DIGI_CARD],dev_info[DIGI_IO],dev_info[DIGI_IRQ],dev_info[DIGI_DMA],dev_info[DIGI_DRQ])); sfx_card =
740     FALSE; curr_sfx_vol = 0;
741                }
742             else  // note this use to allocate double buffer space here
743           {
744              snd_set_digital_channels(cur_digi_channels);
745     //         digi_gain = TRUE;             // ie look at detail and stuff
746           }
747             }
748        else
749           curr_sfx_vol = 0;
750 
751        if (sfx_card)
752        {
753           sfx_on=TRUE;
754     #ifdef AUDIOLOGS
755           audiolog_init();
756     #endif
757        }
758     */
759     if (gShockPrefs.soBackMusic) {
760         //	if (music_card)
761         //	{
762         if (MacTuneInit() == 0) // If no error, go ahead and start up.
763         {
764             music_on = mlimbs_on = TRUE;
765             mlimbs_AI_init();
766         } else // else turn off the music globals and prefs
767         {
768             gShockPrefs.soBackMusic = FALSE;
769             SavePrefs();
770             music_on = mlimbs_on = FALSE;
771         }
772         //	}
773     } else {
774         music_on = mlimbs_on = FALSE;
775     }
776     return (OK);
777 }
778 
779 /* KLC - doesn't do anything
780 void music_free(void)
781 {
782    DatapathFree(&music_dpath);
783 }
784 */
785