]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/digiallg.c
don't use hardcoded descriptions of joystick buttons/axes
[btb/d2x.git] / arch / dos / digiallg.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <malloc.h>
17 #include <string.h>
18 #include <ctype.h>
19
20 #include "fix.h"
21 #include "object.h"
22 #include "mono.h"
23 #include "timer.h"
24 #include "joy.h"
25 #include "digi.h"
26 #include "sounds.h"
27 #include "args.h"
28 #include "key.h"
29 #include "newdemo.h"
30 #include "game.h"
31 #include "u_dpmi.h"
32 #include "error.h"
33 #include "wall.h"
34 #include "cfile.h"
35 #include "piggy.h"
36 #include "text.h"
37 #include "midiallg.h"
38
39 #include "kconfig.h"
40
41 #define _DIGI_MAX_VOLUME 128 // set lower to have difference with > F1_0 sounds
42
43 #define MIN_VOLUME 10 // minimal volume to be played (in 0-F1_0(?) range)
44
45 // patch files
46 #define  _MELODIC_PATCH       "melodic.bnk"
47 #define  _DRUM_PATCH          "drum.bnk"
48 #define  _DIGDRUM_PATCH       "drum32.dig"
49
50  
51 static int      Digi_initialized                = 0;
52 static int      digi_atexit_called      = 0;                    // Set to 1 if atexit(digi_close) was called
53
54 int digi_driver_board                           = 0;
55 int digi_driver_port                                    = 0;
56 int digi_driver_irq                                     = 0;
57 int digi_driver_dma                                     = 0;
58 //int digi_midi_type                                      = 0;                    // Midi driver type
59 //int digi_midi_port                                      = 0;                    // Midi driver port
60 static int digi_max_channels            = 8;
61 //static int digi_driver_rate             = 11025;                        // rate to use driver at
62 //static int digi_dma_buffersize  = 4096;                 // size of the dma buffer to use (4k)
63 int digi_timer_rate                                     = 9943;                 // rate for the timer to go off to handle the driver system (120 Hz)
64 static int digi_volume                          = _DIGI_MAX_VOLUME;             // Max volume
65 //static int midi_volume                          = 128/2;                                                // Max volume
66 //static int midi_system_initialized              = 0;
67 //static int digi_system_initialized              = 0;
68 static int timer_system_initialized             = 0;
69 static int digi_sound_locks[MAX_SOUNDS];
70 //char digi_last_midi_song[16] = "";
71 //char digi_last_melodic_bank[16] = "";
72 //char digi_last_drum_bank[16] = "";
73 char *digi_driver_path = NULL;
74
75 extern int midi_volume;
76
77 //static void * lpInstruments = NULL;             // pointer to the instrument file
78 //static int InstrumentSize = 0;
79 //static void * lpDrums = NULL;                           // pointer to the drum file
80 //static int DrumSize = 0;
81
82 // handle for the initialized MIDI song
83 //MIDI *SongHandle = NULL;
84
85
86 // a channel (voice) id is an int in Allegro
87 typedef int CHANNEL;
88 #define VALID_CHANNEL(ch) (ch >= 0)
89 #define INVALID_CHANNEL -1
90
91 #define DIGI_SLOTS DIGI_VOICES
92
93 // next_handle is a Descent internal number (hereafter reffered to as slot),
94 // which indexes into SampleHandles, SoundNums and SoundVolumes.
95 // only digi_max_channels entries are used.
96 // SampleHandles points to sounddriver handles (voices)
97 static int next_handle = 0;
98 static CHANNEL SampleHandles[DIGI_SLOTS] = {
99     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
100     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
101     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
102     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
103     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
104     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
105     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
106     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL };
107 static int SoundNums[DIGI_SLOTS] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
108 static uint SoundVolumes[DIGI_SLOTS] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
109
110 void digi_reset_digi_sounds();
111 int verify_channel_not_used_by_soundobjects( int channel );
112
113 void digi_close() {
114         if (!Digi_initialized) return;
115
116         remove_sound();
117         Digi_initialized = 0;
118
119         if ( timer_system_initialized ) {
120                 // Remove timer...
121                 timer_set_function( NULL );
122     }
123     timer_system_initialized = 0;
124 }
125
126 /* initialize sound system. 0=ok, 1=error */
127 int digi_init() {
128         int i;
129
130         if (!timer_system_initialized)
131         {
132             allg_snd_init();
133             timer_system_initialized = 1;
134         }
135         if (!Digi_initialized) {
136                 // amount of voices we need
137                 // 16 for normal sounds and 16 for SoundObjects (fan, boss)
138                 // for DIGMID we sacrify some sounds (32 is the max).
139 //                reserve_voices(allegro_using_digmid() ? 16 : 32, -1);
140                 if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL))
141                         return 1;
142                 set_volume(255, -1);
143                 digi_driver_board = digi_card; // only for 0, !=0
144                 digi_midi_type = midi_card; // only for 0, !=0
145         }
146         Digi_initialized = 1;
147
148
149         if (!digi_atexit_called)        {
150                 atexit( digi_close );
151                 digi_atexit_called = 1;
152         }
153
154         digi_init_sounds();
155         digi_set_midi_volume( midi_volume );
156
157         for (i=0; i<MAX_SOUNDS; i++ )
158                 digi_sound_locks[i] = 0;
159         digi_reset_digi_sounds();
160
161         return 0;
162 }
163
164 // Toggles sound system on/off
165 void digi_reset()       
166 {
167         if ( Digi_initialized ) {
168                 digi_reset_digi_sounds();
169                 digi_close();
170                 mprintf( (0, "Sound system DISABLED.\n" ));
171         } else {
172                 digi_init();
173                 mprintf( (0, "Sound system ENABLED.\n" ));
174         }
175 }
176
177 int digi_total_locks = 0;
178
179 ubyte * digi_lock_sound_data( int soundnum )
180 {
181         int i;
182
183         if ( !Digi_initialized ) return NULL;
184         if ( digi_driver_board <= 0 )   return NULL;
185
186         if ( digi_sound_locks[soundnum] == 0 )  {
187                 digi_total_locks++;
188                 //mprintf(( 0, "Total sound locks = %d\n", digi_total_locks ));
189                 i = dpmi_lock_region( GameSounds[soundnum].data, GameSounds[soundnum].len );
190                 if ( !i ) Error( "Error locking sound %d\n", soundnum );
191         }
192         digi_sound_locks[soundnum]++;
193         return GameSounds[soundnum].data;
194 }
195
196 void digi_unlock_sound_data( int soundnum )
197 {
198         int i;
199
200         if ( !Digi_initialized ) return;
201         if ( digi_driver_board <= 0 )   return;
202
203         Assert( digi_sound_locks[soundnum] > 0 );
204
205         if ( digi_sound_locks[soundnum] == 1 )  {
206                 digi_total_locks--;
207                 //mprintf(( 0, "Total sound locks = %d\n", digi_total_locks ));
208                 i = dpmi_unlock_region( GameSounds[soundnum].data, GameSounds[soundnum].len );
209                 if ( !i ) Error( "Error unlocking sound %d\n", soundnum );
210         }
211         digi_sound_locks[soundnum]--;
212 }
213
214
215 void digi_reset_digi_sounds() {
216         int i;
217
218         for (i = 0; i < DIGI_SLOTS; i++) {
219                 if (VALID_CHANNEL(SampleHandles[i])) {
220                         deallocate_voice(SampleHandles[i]);
221                         SampleHandles[i] = INVALID_CHANNEL;
222                 }
223                 if (SoundNums[i] != -1) {
224                         digi_unlock_sound_data(SoundNums[i]);
225                         SoundNums[i] = -1;
226         }
227         }
228         for (i=0; i<MAX_SOUNDS; i++ )   {
229                 Assert( digi_sound_locks[i] == 0 );
230         }
231 }
232
233 void digi_set_max_channels(int n) {
234         digi_max_channels       = n;
235
236         if ( digi_max_channels < 1 ) 
237                 digi_max_channels = 1;
238         if ( digi_max_channels > DIGI_VOICES)
239                 digi_max_channels = DIGI_VOICES;
240 }
241
242 int digi_get_max_channels()
243 {
244         return digi_max_channels;
245 }
246
247 void digi_stop_all_channels()
248 {
249         int i;
250
251         for (i = 0; i < MAX_SOUND_SLOTS; i++)
252                 digi_stop_sound(i);
253 }
254
255 int get_free_slot() {
256         int ntries = 0;
257         int ret_slot;
258
259 TryNextChannel:
260         // sound playing on slot <next_handle>?
261         if ( (VALID_CHANNEL(SampleHandles[next_handle])) &&
262              (voice_check(SampleHandles[next_handle])) ) {
263                 // don't use this slot if loud sound
264                 if ( (SoundVolumes[next_handle] > digi_volume) &&
265                          (ntries<digi_max_channels) )  {
266                         mprintf(( 0, "Not stopping loud sound %d (%d).\n", next_handle, SoundNums[next_handle]));
267                         next_handle++;
268                         if ( next_handle >= digi_max_channels )
269                                 next_handle = 0;
270                         ntries++;
271                         goto TryNextChannel;
272                 }
273                 //mprintf(( 0, "[SS:%d]", next_handle ));
274                 if (voice_check(next_handle))
275                         mprintf((0,"Sound: deallocating used voice %d sound %d vol %d pos %d/%d\n", next_handle, SoundNums[next_handle], SoundVolumes[next_handle], voice_get_position(next_handle), GameSounds[SoundNums[next_handle]].len));
276                 deallocate_voice(SampleHandles[next_handle]);
277                 SampleHandles[next_handle] = INVALID_CHANNEL;
278         }
279
280         if ( SoundNums[next_handle] != -1 ) {
281                 digi_unlock_sound_data(SoundNums[next_handle]);
282                 SoundNums[next_handle] = -1;
283         }
284         ret_slot = next_handle;
285         next_handle++;
286         if ( next_handle >= digi_max_channels )
287                 next_handle = 0;
288         return ret_slot;
289 }
290
291 CHANNEL digi_start_sound(int soundnum, int volume, int pan) {
292         int i;
293         int channel;
294         int slot;
295
296         volume = fixmul(volume, digi_volume);
297         slot = get_free_slot();
298
299         digi_lock_sound_data(soundnum);
300         channel = play_sample(&GameSounds[soundnum], volume, pan >> 8, 1000, 0);
301         if (channel < 0) {
302                 mprintf(( 1, "NOT ENOUGH SOUND SLOTS!!!\n" ));
303                 digi_unlock_sound_data(soundnum);
304                 return -1;
305         }
306         release_voice(channel);
307
308         //mprintf(( 0, "Starting sound on channel %d\n", channel ));
309         #ifndef NDEBUG
310         verify_channel_not_used_by_soundobjects(channel);
311         #endif
312
313         // find slots pointing to just allocated channel and kill sounds on it
314         // (because they can't be playing right now)
315         for (i=0; i<digi_max_channels; i++ )    {
316                 if (SampleHandles[i] == channel)   {
317                         SampleHandles[i] = INVALID_CHANNEL;
318                         if (SoundNums[i] != -1)   {
319                                 digi_unlock_sound_data(SoundNums[i]);
320                                 SoundNums[i] = -1;
321                         }
322                 }
323         }
324
325         // fill slot with data of just started sample
326         SampleHandles[slot] = channel;
327         SoundNums[slot] = soundnum;
328         SoundVolumes[slot] = volume;
329
330         return channel;
331 }
332
333 // Returns the channel a sound number is playing on, or
334 // -1 if none.
335 int digi_find_channel(int soundno)
336 {
337         if (!digi_initialised)
338                 return -1;
339
340         if (soundno < 0 )
341                 return -1;
342
343         if (GameSounds[soundno].data == NULL)
344         {
345                 Int3();
346                 return -1;
347         }
348
349         //FIXME: not implemented
350         return -1;
351 }
352
353 int digi_is_sound_playing(int soundno)
354 {
355         int i;
356
357         soundno = digi_xlat_sound(soundno);
358
359         for (i = 0; i < DIGI_VOICES; i++)
360                   if (voice_check(i) == &GameSounds[soundno])
361                         return 1;
362         return 0;
363 }
364
365 //-killed- void digi_set_midi_volume( int mvolume )
366 //-killed- {
367 //-killed-         int old_volume = midi_volume;
368 //-killed- 
369 //-killed-         if ( mvolume > 127 )
370 //-killed-                 midi_volume = 127;
371 //-killed-         else if ( mvolume < 0 )
372 //-killed-                 midi_volume = 0;
373 //-killed-         else
374 //-killed-                 midi_volume = mvolume;
375 //-killed- 
376 //-killed-         if ( (digi_midi_type > 0) )        {
377 //-killed-                 if (  (old_volume < 1) && ( midi_volume > 1 ) ) {
378 //-killed-                         if (SongHandle == NULL )
379 //-killed-                                 digi_play_midi_song( digi_last_midi_song, digi_last_melodic_bank, digi_last_drum_bank, 1 );
380 //-killed-                 }
381 //-killed-                 set_volume(-1, midi_volume * 2 + (midi_volume & 1));
382 //-killed-         }
383 //-killed- }
384
385 void digi_set_digi_volume( int dvolume )
386 {
387         dvolume = fixmuldiv( dvolume, _DIGI_MAX_VOLUME, 0x7fff);
388         if ( dvolume > _DIGI_MAX_VOLUME )
389                 digi_volume = _DIGI_MAX_VOLUME;
390         else if ( dvolume < 0 )
391                 digi_volume = 0;
392         else
393                 digi_volume = dvolume;
394
395         if ( !Digi_initialized ) return;
396         if ( digi_driver_board <= 0 )   return;
397
398         digi_sync_sounds();
399 }
400
401 // 0-0x7FFF
402 void digi_set_volume( int dvolume, int mvolume )
403 {
404         digi_set_midi_volume( mvolume );
405         digi_set_digi_volume( dvolume );
406 //      mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
407 }
408
409 int digi_is_channel_playing(int channel)
410 {
411         int i;
412
413         if (!digi_initialised)
414                 return 0;
415
416         //FIXME: not implemented
417         return 0;
418 }
419
420 void digi_set_channel_volume(int channel, int volume)
421 {
422         if (!digi_initialised)
423                 return;
424
425         //FIXME: not implemented
426 }
427
428 void digi_set_channel_pan(int channel, int pan)
429 {
430         if (!digi_initialised)
431                 return;
432
433         //FIXME: not implemented
434 }
435
436 void digi_stop_sound(int channel)
437 {
438         //FIXME: not implemented
439 }
440
441 void digi_end_sound(int channel)
442 {
443         if (!digi_initialised)
444                 return;
445
446         //FIXME: not implemented
447 }
448
449 //-killed- void digi_stop_current_song()
450 //-killed- {
451 //-killed-         if (SongHandle) {
452 //-killed-                 destroy_midi(SongHandle);
453 //-killed-                 SongHandle = NULL;
454 //-killed-         }
455 //-killed- }
456 //-killed- 
457 //-killed- void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop )
458 //-killed- {
459 //-killed-         //char fname[128];
460 //-killed- 
461 //-killed-         if (!Digi_initialized) return;
462 //-killed-         if ( digi_midi_type <= 0 )      return;
463 //-killed- 
464 //-killed-         digi_stop_current_song();
465 //-killed- 
466 //-killed-         if ( filename == NULL ) return;
467 //-killed- 
468 //-killed-         strcpy( digi_last_midi_song, filename );
469 //-killed-         strcpy( digi_last_melodic_bank, melodic_bank );
470 //-killed-         strcpy( digi_last_drum_bank, drum_bank );
471 //-killed- 
472 //-killed-         if ( midi_volume < 1 )
473 //-killed- 
474 //-killed-         SongHandle = NULL;
475 //-killed- 
476 //-killed- #if 0 /* needs bank loading to sound right */
477 //-killed-         if (midi_card <= 4) { /* FM cards */
478 //-killed-                 int sl;
479 //-killed-                 sl = strlen( filename );
480 //-killed-                 strcpy( fname, filename ); 
481 //-killed-                 fname[sl-1] = 'q';
482 //-killed-                 SongHandle = load_hmp(fname);
483 //-killed-         }
484 //-killed- #endif
485 //-killed- 
486 //-killed-         if ( !SongHandle  )
487 //-killed-                 SongHandle = load_hmp(filename);
488 //-killed- 
489 //-killed-         if (SongHandle) {
490 //-killed-                 if (play_midi(SongHandle, loop)) {
491 //-killed-                         destroy_midi(SongHandle);
492 //-killed-                         SongHandle = NULL;
493 //-killed-                 }
494 //-killed-         }
495 //-killed-         if (!SongHandle) {
496 //-killed-                         mprintf( (1, "\nAllegro Error : %s", allegro_error ));
497 //-killed-         }
498 //-killed- }
499
500
501 #ifndef NDEBUG
502 void digi_debug()
503 {
504         int i;
505         int n_voices = 0;
506
507         if (!digi_initialised)
508                 return;
509
510         for (i = 0; i < digi_max_channels; i++)
511         {
512                 if (digi_is_channel_playing(i))
513                         n_voices++;
514         }
515
516         mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32)      ", n_voices, digi_max_channels, -1));
517         //mprintf_at((0, 3, 0, "DIGI: Number locked sounds:  %d                          ", digi_total_locks ));
518 }
519
520 int verify_channel_not_used_by_soundobjects( int channel )
521 {
522         int i;
523         if (digi_driver_board>0)        {
524                 for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
525                         if ( SoundObjects[i].flags & SOF_USED ) {
526                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
527                                         if ( SoundObjects[i].handle == channel )        {
528                                                 mprintf(( 0, "ERROR STARTING SOUND CHANNEL ON USED SLOT!!\n" ));
529                                                 Int3(); // Get John!
530                                         }
531                                 }
532                         }
533                 }
534         }
535         return 0;
536 }
537 #endif
538
539 #if 0 // hud sound debug info
540 #include "gr.h"
541 #include "gamefont.h"
542 #define VIRTUAL_VOICES 256
543 void show_digi_info() {
544         int i, active_slots = 0, done_slots = 0, allg_used = 0;
545
546         for (i=0; i<DIGI_SLOTS; i++)
547                 if (VALID_CHANNEL(SampleHandles[i])) {
548                         active_slots++;
549                         if (!voice_check(SampleHandles[i]))
550                                 done_slots++;
551                 }
552         for (i=0; i<VIRTUAL_VOICES; i++)
553                 if (voice_check(i))
554                         allg_used++;
555
556
557         gr_set_curfont( GAME_FONT );
558         gr_set_fontcolor(gr_getcolor(0,31,0),-1 );
559         gr_printf(0,32,"voices: real:%d exp:%d locks:%d sluse:%d sldone:%d aused:%d slnxt:%d",
560          digi_driver->voices, digi_max_channels, digi_total_locks,
561          active_slots,done_slots,allg_used, next_handle);
562 }
563 #endif