1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: I_sound.c 1417 2019-01-29 08:00:14Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: I_sound.c,v $
21 // Revision 1.5  2003/07/13 13:18:59  hurdler
22 // Revision 1.4  2001/03/30 17:12:52  bpereira
23 // Revision 1.3  2000/03/06 15:32:56  hurdler
24 // Revision 1.2  2000/02/27 00:42:11  hurdler
25 // Revision 1.1.1.1  2000/02/22 20:32:33  hurdler
26 // Initial import into CVS (v1.29 pr3)
27 //
28 //
29 // DESCRIPTION:
30 //      interface level code for sound
31 //
32 //-----------------------------------------------------------------------------
33 
34 #include "doomincl.h"
35   // stdio, stdlib, strings, defines
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 
41 #include <math.h>
42 
43 #include "doomstat.h"
44 #include "i_system.h"
45 #include "i_sound.h"
46 #include "z_zone.h"
47 #include "m_argv.h"
48 #include "m_misc.h"
49 #include "w_wad.h"
50 #include "s_sound.h"
51 #include "console.h"
52 
53 //### let's try with Allegro ###
54 #define  alleg_mouse_unused
55 #define  alleg_timer_unused
56 #define  alleg_keyboard_unused
57 #define  alleg_joystick_unused
58 #define  alleg_gfx_driver_unused
59 #define  alleg_palette_unused
60 #define  alleg_graphics_unused
61 #define  alleg_vidmem_unused
62 #define  alleg_flic_unused
63 //#define  alleg_sound_unused    we use it
64 #define  alleg_file_unused
65 #define  alleg_datafile_unused
66 #define  alleg_math_unused
67 #define  alleg_gui_unused
68 #include <allegro.h>
69 //### end of Allegro include ###
70 
71 #include "qmus2mid.h"
72 //#include "loadmus.h"
73 
74 //allegro has 256 virtual voices
75 // warning should by a power of 2
76 #define VIRTUAL_VOICES 256
77 #define VOICESSHIFT 8
78 
79 // Needed for calling the actual sound output.
80 #define SAMPLECOUNT    512
81 
82 
83 
84 //
85 // this function converts raw 11khz, 8-bit data to a SAMPLE* that allegro uses
86 // it is need cuz allegro only loads samples from wavs and vocs
87 //added:11-01-98: now reads the frequency from the rawdata header.
88 //   dsdata points a 4 unsigned short header:
89 //    +0 : value 3 what does it mean?
90 //    +2 : sample rate, either 11025 or 22050.
91 //    +4 : number of samples, each sample is a single byte since it's 8bit
92 //    +6 : value 0
raw2SAMPLE(unsigned char * dsdata,int len)93 SAMPLE *raw2SAMPLE(unsigned char *dsdata, int len)
94 {
95     SAMPLE *spl;
96 
97     spl=Z_Malloc(sizeof(SAMPLE),PU_STATIC,NULL);
98     spl->bits = 8;
99     spl->stereo = 0;
100     spl->freq = *((unsigned short*)dsdata+1);   //mostly 11025, but some at 22050.
101     spl->len = len-8;
102     spl->priority = 255;                //priority;
103     spl->loop_start = 0;
104     spl->loop_end = len-8;
105     spl->param = -1;
106     spl->data=(void *)(dsdata+8);       //skip the 8bytes header
107 
108     return spl;
109 }
110 
111 
112 //  This function loads the sound data from the WAD lump,
113 //  for single sound.
114 //
I_GetSfx(sfxinfo_t * sfx)115 void I_GetSfx (sfxinfo_t*  sfx)
116 {
117     byte * dssfx;
118 
119     S_GetSfxLump( sfx );  // lump to sfx
120     if( ! sfx->data ) return;
121     // fix the data and length for this mixer
122 
123     dssfx = (byte*) sfx->data;
124     //_go32_dpmi_lock_data(dssfx, sfx->length);
125 
126     // convert raw data and header from Doom sfx to a SAMPLE for Allegro
127     sfx->data = (void*) raw2SAMPLE (dssfx, sfx->length);
128     // data holds SAMPLE struct, and dssfx
129 }
130 
131 
I_FreeSfx(sfxinfo_t * sfx)132 void I_FreeSfx (sfxinfo_t* sfx)
133 {
134     byte*    dssfx;
135 
136     if( ! VALID_LUMP(sfx->lumpnum) )
137         return;
138 
139     // free sample data
140     if( sfx->data )
141     {
142         dssfx = (byte*) ((SAMPLE *)sfx->data)->data - 8;  // undo skip header
143         Z_Free (dssfx);
144         // Allegro SAMPLE structure
145         Z_Free (sfx->data);
146     }
147 
148     sfx->data = NULL;
149     sfx->lumpnum = NO_LUMP;
150 }
151 
152 
I_SetSfxVolume(int volume)153 void I_SetSfxVolume(int volume)
154 {
155     if(nosoundfx)
156         return;
157 
158     // Can use mix_sfxvolume (0..31), or set local volume vars.
159     // mix_sfxvolume = volume;
160     set_volume (volume*255/31,-1);
161 }
162 
163 // MUSIC API - dummy. Some code from DOS version.
I_SetMusicVolume(int volume)164 void I_SetMusicVolume(int volume)
165 {
166     if(nomusic)
167         return;
168 
169     // Now set volume on output device.
170     set_volume (-1, cv_musicvolume.value*255/31);
171 }
172 
173 
174 
175 //
176 // Starting a sound means adding it
177 //  to the current list of active sounds
178 //  in the internal channels.
179 // As the SFX info struct contains
180 //  e.g. a pointer to the raw data,
181 //  it is ignored.
182 // As our sound handling does not handle
183 //  priority, it is ignored.
184 // Pitching (that is, increased speed of playback)
185 //  is set, but currently not used by mixing.
186 //
I_StartSound(int id,int vol,int sep,int pitch,int priority)187 int I_StartSound ( int           id,
188                    int           vol,
189                    int           sep,
190                    int           pitch,
191                    int           priority )
192 {
193   int voice;
194 
195   if(nosoundfx)
196       return 0;
197 
198   // UNUSED
199   priority = 0;
200 
201   pitch=(pitch-128)/2+128;
202 #ifdef SURROUND_SOUND
203   if( sep > 128 )   sep = 0;   // No SURROUND
204 #endif
205   // Allegro center is 128.
206   voice=play_sample(S_sfx[id].data,vol,sep+128,(pitch*1000)/128,0);
207 
208   // Returns a handle
209   return (id<<VOICESSHIFT)+voice;
210 }
211 
212 // You need the handle returned by StartSound.
I_StopSound(int handle)213 void I_StopSound (int handle)
214 {
215   int voice=handle & (VIRTUAL_VOICES-1);
216 
217   if(nosoundfx)
218       return;
219 
220   if(voice_check(voice)==S_sfx[handle>>VOICESSHIFT].data)
221     deallocate_voice(voice);
222 }
223 
224 // You need the handle returned by StartSound.
I_SoundIsPlaying(int handle)225 int I_SoundIsPlaying(int handle)
226 {
227   if(nosoundfx)
228       return FALSE;
229 
230   if(voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data)
231       return TRUE;
232   return FALSE;
233 }
234 
235 
236 //
237 // This function loops all active (internal) sound
238 //  channels, retrieves a given number of samples
239 //  from the raw sound data, modifies it according
240 //  to the current (internal) channel parameters,
241 //  mixes the per channel samples into the global
242 //  mixbuffer, clamping it to the allowed range,
243 //  and sets up everything for transferring the
244 //  contents of the mixbuffer to the (two)
245 //  hardware channels (left and right, that is).
246 //
247 //  allegro does this now
248 //
I_UpdateSound(void)249 void I_UpdateSound( void )
250 {
251 }
252 
253 
254 //
255 // This would be used to write out the mixbuffer
256 //  during each game loop update.
257 // Updates sound buffer and audio device at runtime.
258 // It is called during Timer interrupt with SNDINTR.
259 // Mixing now done synchronous, and
260 //  only output be done asynchronous?
261 //
262 
I_SubmitSound(void)263 void I_SubmitSound( void )
264 {
265   //this should no longer be necessary cuz allegro is doing all the sound mixing now
266 }
267 
268 // cut and past from ALLEGRO he don't share it :(
absolute_freq(int freq,SAMPLE * spl)269 static inline int absolute_freq(int freq, SAMPLE *spl)
270 {
271    if (freq == 1000)
272       return spl->freq;
273    else
274       return (spl->freq * freq) / 1000;
275 }
276 
277 // You need the handle returned by StartSound.
278 //  sep : separation, +/- 127, SURROUND_SEP special operation
I_UpdateSoundParams(int handle,int vol,int sep,int pitch)279 void I_UpdateSoundParams( int   handle,
280                           int   vol,
281                           int   sep,
282                           int   pitch)
283 {
284   int voice=handle & (VIRTUAL_VOICES-1);
285   int numsfx=handle>>VOICESSHIFT;
286 
287   if(nosoundfx)
288       return;
289 
290   if(voice_check(voice)==S_sfx[numsfx].data)
291   {
292     voice_set_volume(voice, vol);
293 #ifdef SURROUND_SOUND
294     if( sep > 128 )   sep = 0;  // No SURROUND
295 #endif
296     // Allegro center is 128.
297     voice_set_pan(voice, sep+128);
298     voice_set_frequency(voice, absolute_freq(pitch*1000/128
299                              , S_sfx[numsfx].data));
300   }
301 }
302 
303 
I_ShutdownSound(void)304 void I_ShutdownSound(void)
305 {
306   // Wait till all pending sounds are finished.
307 
308   //added:03-01-98:
309   if( !sound_started )
310       return;
311 
312   //added:08-01-98: remove_sound() explicitly because we don't use
313   //                Allegro's allegro_exit();
314   remove_sound();
315   sound_started = false;
316 }
317 
I_StartupSound()318 void I_StartupSound()
319 {
320     int    sfxcard,midicard;
321     char   err[255];
322 
323     if (nosoundfx)
324         sfxcard=DIGI_NONE;
325     else
326         sfxcard=DIGI_AUTODETECT;
327 
328     if (nomusic)
329         midicard=MIDI_NONE;
330     else
331         midicard=MIDI_AUTODETECT; //DetectMusicCard();
332 
333     // Secure and configure sound device first.
334     CONS_Printf("I_StartupSound: ");
335 
336     //Fab:25-04-98:note:install_sound will check for sound settings
337     //    in the sound.cfg or allegro.cfg, in the current directory,
338     //    or the directory pointed by 'ALLEGRO' env var.
339     if (install_sound(sfxcard,midicard,NULL)!=0)
340     {
341         sprintf (err,"Sound init error : %s\n",allegro_error);
342         CONS_Error (err);
343         nosoundfx=true;
344     }
345     else
346         CONS_Printf(" configured audio device\n" );
347 
348     //added:08-01-98:we use a similar startup/shutdown scheme as Allegro.
349     I_AddExitFunc(I_ShutdownSound);
350     sound_started = true;
351 }
352 
353 
354 
355 
356 //
357 // MUSIC API.
358 // Still no music done.
359 // Remains. Dummies.
360 //
361 
362 MIDI* currsong;   //im assuming only 1 song will be played at once
363 static int      islooping=0;
364 static int      musicdies=-1;
365 int             music_started=0;
366 char*           musicbuffer;
367 
368 
369 /* load_midi_mem:
370  *  Loads a standard MIDI file from memory, returning a pointer to
371  *  a MIDI structure, *  or NULL on error.
372  *  It is the load_midi from Allegro modified to load it from memory
373  */
load_midi_mem(char * mempointer,int * e)374 MIDI *load_midi_mem(char *mempointer,int *e)
375 {
376    int c;
377    long data=0;
378    char *fp;
379    MIDI *midi;
380    int num_tracks=0;
381 
382    fp = mempointer;
383    if (!fp)
384       return NULL;
385 
386    midi = malloc(sizeof(MIDI));              /* get some memory */
387    if (!midi)
388       return NULL;
389 
390    for (c=0; c<MIDI_TRACKS; c++) {
391       midi->track[c].data = NULL;
392       midi->track[c].len = 0;
393    }
394 
395    fp+=4+4;   // header size + 'chunk' size
396 
397    swab(fp,&data,2);     // convert to intel-endian
398    fp+=2;                                      /* MIDI file type */
399    if ((data != 0) && (data != 1)) // only type 0 and 1 are suported
400      return NULL;
401 
402    swab(fp,&num_tracks,2);                     /* number of tracks */
403    fp+=2;
404    if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
405       return NULL;
406 
407    swab(fp,&data,2);                          /* beat divisions */
408    fp+=2;
409    midi->divisions = ABS(data);
410 
411    for (c=0; c<num_tracks; c++) {            /* read each track */
412       if (memcmp(fp, "MTrk", 4))
413          return NULL;
414       fp+=4;
415 
416 //      swab(fp,&data,4);       don't work !!!!??
417       ((char *)&data)[0]=fp[3];
418       ((char *)&data)[1]=fp[2];
419       ((char *)&data)[2]=fp[1];
420       ((char *)&data)[3]=fp[0];
421       fp+=4;
422 
423       midi->track[c].len = data;
424 
425       midi->track[c].data=fp;
426       fp+=data;
427    }
428 
429    lock_midi(midi);
430    return midi;
431 }
432 
433 #define MIDBUFFERSIZE   128*1024L
434 
I_InitMusic(void)435 void I_InitMusic(void)
436 {
437     if(nomusic)
438        return;
439 
440     // initialisation of midicard by I_StartupSound
441     musicbuffer=(char *)Z_Malloc(MIDBUFFERSIZE,PU_STATIC,NULL);
442 
443     _go32_dpmi_lock_data(musicbuffer,MIDBUFFERSIZE);
444     I_AddExitFunc(I_ShutdownMusic);
445     music_started = true;
446 }
447 
I_ShutdownMusic(void)448 void I_ShutdownMusic(void)
449 {
450     if( !music_started )
451         return;
452 
453     I_StopSong(1);
454 
455     music_started=false;
456 }
457 
I_PlaySong(int handle,int looping)458 void I_PlaySong(int handle, int looping)
459 {
460     if(nomusic)
461         return;
462 
463     islooping=looping;
464     musicdies = gametic + TICRATE*30;
465     play_midi(currsong,looping);
466 }
467 
I_PauseSong(int handle)468 void I_PauseSong (int handle)
469 {
470     if(nomusic)
471         return;
472 
473     midi_pause();
474 }
475 
I_ResumeSong(int handle)476 void I_ResumeSong (int handle)
477 {
478     if(nomusic)
479         return;
480 
481     midi_resume();
482 }
483 
I_StopSong(int handle)484 void I_StopSong(int handle)
485 {
486     if(nomusic)
487         return;
488 
489     islooping = 0;
490     musicdies = 0;
491     stop_midi();
492 }
493 
494 // Is the song playing?
I_QrySongPlaying(int handle)495 int I_QrySongPlaying(int handle)
496 {
497     if(nomusic)
498         return 0;
499 
500     //return islooping || musicdies > gametic;
501     return (midi_pos==-1);
502 }
503 
I_UnRegisterSong(int handle)504 void I_UnRegisterSong(int handle)
505 {
506     if(nomusic)
507         return;
508 
509 //    destroy_midi(currsong);
510 }
511 
I_RegisterSong(void * data,int len)512 int I_RegisterSong(void* data,int len)
513 {
514     int e;
515     ULONG midlength;
516     if(nomusic)
517         return 1;
518 
519     if(memcmp(data,"MUS",3)==0)
520     {
521         // convert mus to mid with a wonderfull function
522         // thanks to S.Bacquet for the source of qmus2mid
523         // convert mus to mid and load it in memory
524         e = qmus2mid((char *)data, len, 89, 0, MIDBUFFERSIZE,
525 	    /*INOUT*/ musicbuffer, &midlength);
526         if( e != QM_success )
527         {
528             CONS_Printf("Cannot convert mus to mid, converterror :%d\n",e);
529             return 0;
530         }
531         currsong=load_midi_mem(musicbuffer,&e);
532     }
533     else
534     // supprot mid file in WAD !!!
535     if(memcmp(data,"MThd",4)==0)
536     {
537         currsong=load_midi_mem(data,&e);
538     }
539     else
540     {
541         CONS_Printf("Music Lump is not MID or MUS lump\n");
542         return 0;
543     }
544 
545     if(currsong==NULL)
546     {
547         CONS_Printf("Not a valid mid file : %d\n",e);
548         return 0;
549     }
550 
551     return 1;
552 }
553 
554 #ifdef FMOD_SOUND
555 //Hurdler: TODO
I_StartFMODSong()556 void I_StartFMODSong()
557 {
558     CONS_Printf("I_StartFMODSong: Not yet supported under DOS.\n");
559 }
560 
I_StopFMODSong()561 void I_StopFMODSong()
562 {
563     CONS_Printf("I_StopFMODSong: Not yet supported under DOS.\n");
564 }
I_SetFMODVolume(int volume)565 void I_SetFMODVolume(int volume)
566 {
567     CONS_Printf("I_SetFMODVolume: Not yet supported under DOS.\n");
568 }
569 #endif
570 
571