1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_sound.c 1524 2020-05-09 12:07:09Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2000-2016 by Doom Legacy team
8 //
9 // This source is available for distribution and/or modification
10 // only under the terms of the DOOM Source Code License as
11 // published by id Software. All rights reserved.
12 //
13 // The source is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
16 // for more details.
17 //
18 // $Log: i_sound.c,v $
19 // Revision 1.14  2007/01/28 14:45:01  chiphog
20 // This patch addresses 2 issues:
21 // * Separated the SDL and HAVE_MIXER assumptions.  We can now compile with
22 //   SDL=1 but without specifying HAVE_MIXER=1.
23 // * Fixed the playing of MIDI (from MUS) music under SDL.  One needs to
24 //   compile with SDL=1 and HAVE_MIXER=1 to get SDL music.  This involved
25 //   two things:
26 //   + Removed/replaced the conflicting functions explained here:
27 //     http://jonatkins.org/SDL_mixer/SDL_mixer.html#SEC5
28 //   + Backported some SDL mixer mystery magic from legacy-2
29 // This patch has been tested on linux with:
30 // - make LINUX=1                       # you get sound, but it ain't SDL
31 // - make LINUX=1 SDL=1                 # you get SDL sound but no music
32 // - make LINUX=1 SDL=1 HAVE_MIXER=1    # you get SDL sound and SDL music
33 // Compiling with HAVE_MIXER=1 but without SDL=1 will fail.
34 //
35 // Revision 1.13  2006/07/22 15:38:07  hurdler
36 // Quick fix for SDL_mixer compiling issue
37 //
38 // Revision 1.12  2004/04/18 12:53:42  hurdler
39 // fix Heretic issue with SDL and OS/2
40 //
41 // Revision 1.11  2003/07/13 13:16:15  hurdler
42 // Revision 1.10  2001/08/20 20:40:42  metzgermeister
43 //
44 // Revision 1.9  2001/05/16 22:33:35  bock
45 // Initial FreeBSD support.
46 //
47 // Revision 1.8  2001/05/14 19:02:58  metzgermeister
48 //   * Fixed floor not moving up with player on E3M1
49 //   * Fixed crash due to oversized string in screen message ... bad bug!
50 //   * Corrected some typos
51 //   * fixed sound bug in SDL
52 //
53 // Revision 1.7  2001/04/14 14:15:14  metzgermeister
54 // fixed bug no sound device
55 //
56 // Revision 1.6  2001/04/09 20:21:56  metzgermeister
57 // dummy for I_FreeSfx
58 //
59 // Revision 1.5  2001/03/25 18:11:24  metzgermeister
60 //   * SDL sound bug with swapped stereo channels fixed
61 //   * separate hw_trick.c now for HW_correctSWTrick(.)
62 //
63 // Revision 1.4  2001/03/09 21:53:56  metzgermeister
64 // Revision 1.3  2000/11/02 19:49:40  bpereira
65 // Revision 1.2  2000/09/10 10:56:00  metzgermeister
66 // Revision 1.1  2000/08/21 21:17:32  metzgermeister
67 // Initial import to CVS
68 //
69 //
70 // DESCRIPTION:
71 //      System interface for sound.
72 //
73 //-----------------------------------------------------------------------------
74 
75 #include <math.h>
76 #include <unistd.h>
77 
78 #include <SDL.h>
79 #include <SDL_audio.h>
80 #include <SDL_mutex.h>
81 #include <SDL_version.h>
82 #if ((SDL_MAJOR_VERSION*100)+(SDL_MINOR_VERSION*10)) < 120
83 # include <SDL_byteorder.h>
84 #else
85 # include <SDL_endian.h>
86 #endif
87 
88 #ifdef HAVE_MIXER
89 # define  USE_RWOPS
90 # include <SDL_mixer.h>
91 #endif
92 
93 #include "doomincl.h"
94 #include "doomstat.h"
95 
96 #include "i_system.h"
97 #include "i_sound.h"
98 #include "m_argv.h"
99 #include "m_misc.h"
100 #include "m_swap.h"
101 #include "w_wad.h"
102 
103 #include "s_sound.h"
104 
105 #include "d_main.h"
106 #include "z_zone.h"
107 
108 #include "qmus2mid.h"
109 
110 
111 
112 // MIDI music buffer
113 #define MIDBUFFERSIZE   (128*1024)
114 
115 #define MUSIC_FADE_TIME 400 // ms
116 
117 // The number of internal mixing channels,
118 //  mixing buffer, and the samplerate of the raw data.
119 
120 // Doom sound effects
121 #define DOOM_SAMPLERATE 11025 // Hz
122 
123 // Needed for calling the actual sound output.
124 // max. number of simultaneous sounds
125 #define NUM_CHANNELS  16
126 #define CHANNEL_NUM_MASK  (NUM_CHANNELS-1)
127 #define SAMPLERATE    22050 // Hz
128 // requested audio buffer size (512 means about 46 ms at 11 kHz)
129 #define SAMPLECOUNT   512
130 
131 typedef struct {
132 
133   // The channel data pointers, start and end.
134   byte * data_ptr;  // NULL when inactive
135   byte * data_end;
136 
137   unsigned int step;  // The channel step amount...
138   unsigned int step_remainder;   // ... and a 0.16 bit remainder of last step.
139 
140   // When the channel starts playing, and there are too many sounds,
141   // determine which to kill by oldest and priority.
142   unsigned int age_priority;
143 
144   // The data sample rate
145   unsigned int samplerate;
146 
147   // The sound in channel handles,
148   //  determined on registration,
149   //  might be used to unregister/stop/modify,
150   // Lowest bits are the channel num.
151   int handle;
152 
153   // SFX id of the playing sound effect.
154   // Used to catch duplicates (like chainsaw).
155   int sfxid;
156 
157   // Hardware left and right channel volume lookup.
158   int * leftvol_lookup;
159   int * rightvol_lookup;
160 
161 #ifdef SURROUND_SOUND
162   byte  invert_right;
163 #endif
164 
165 } mix_channel_t;
166 
167 static mix_channel_t  mix_channel[ NUM_CHANNELS ];  // channel
168 
169 
170 // Pitch to stepping lookup, 16.16 fixed point
171 static Sint32 steptable[256];
172 
173 // Volume lookups.
174 static int vol_lookup[128 * 256];
175 
176 // Buffer for MIDI
177 static byte *midi_buffer;
178 
179 // Flags for the -nosound and -nomusic options
180 extern boolean nosoundfx;
181 extern boolean nomusic;
182 
183 static boolean musicStarted = false;
184 static boolean soundStarted = false;
185 
186 static unsigned int sound_age = 1000;  // age counter
187 
188 
189 //
190 // SFX API
191 // Note: this was called by S_Init.
192 // However, whatever they did in the
193 // old DPMS based DOS version, this
194 // were simply dummies in the Linux version.
195 // See soundserver initdata().
196 //
197 // Well... To keep compatibility with legacy doom, I have to call this in
198 // I_InitSound since it is not called in S_Init... (emanne@absysteme.fr)
199 
I_SetChannels(void)200 static void I_SetChannels(void)
201 {
202     // Init internal lookups (raw data, mixing buffer, channels).
203     // This function sets up internal lookups used during
204     //  the mixing process.
205     int i, j;
206 
207     if (nosoundfx)
208         return;
209 
210     double base_step = (double)DOOM_SAMPLERATE / (double)SAMPLERATE;
211 
212     // This table provides step widths for pitch parameters.
213     for (i = 0; i < 256; i++)
214     {
215       steptable[i] = (Sint32)(base_step * pow(2.0, ((i-128) / 64.0)) * 65536.0);
216     }
217 
218     // Generates volume lookup tables
219     //  which also turn the u8 samples into s16 samples.
220     for (i = 0; i < 128; i++)
221     {
222         for (j = 0; j < 256; j++)
223         {
224             vol_lookup[i * 256 + j] = (i * (j - 128) * 256) / 127;
225         }
226     }
227 }
228 
I_SetSfxVolume(int volume)229 void I_SetSfxVolume(int volume)
230 {
231     // Can use mix_sfxvolume (0..31), or set local volume vars.
232     // mix_sfxvolume = volume;
233 }
234 
235 
I_GetSfx(sfxinfo_t * sfx)236 void I_GetSfx(sfxinfo_t * sfx)
237 {
238     S_GetSfxLump( sfx ); // lump to sfx
239     // [WDJ] If save sfx->data += 8 to skip header,
240     // then would need to undo it to Free the mem.  Caused Z_Free failure.
241     if( sfx->length > 8 )
242     {
243         sfx->length -= 8;  // length of sound
244     }
245 }
246 
I_FreeSfx(sfxinfo_t * sfx)247 void I_FreeSfx(sfxinfo_t * sfx)
248 {
249     // normal Z_Free in S_FreeSfx
250 }
251 
252 #if 0
253 // cleanly stop a channel
254 static void stop_channel( mix_channel_t * chanp )
255 {
256     chanp->data_ptr = NULL;
257     // Do not release sound lump, it gets used too often,
258     // and would have to check for other sound channels using it.
259 }
260 #endif
261 
262 
263 //
264 // Starting a sound means adding it
265 //  to the current list of active sounds in the internal channels.
266 // Pitching (that is, increased speed of playback)
267 //  is set, but currently not used by mixing.
268 //
269 //  vol : volume, 0..255
270 //  sep : separation, +/- 127, SURROUND_SEP special operation
271 // Return a channel handle.
I_StartSound(sfxid_t sfxid,int vol,int sep,int pitch,int priority)272 int I_StartSound(sfxid_t sfxid, int vol, int sep, int pitch, int priority)
273 {
274     int handle;
275     mix_channel_t  *  chanp;
276     int i;
277     int slot;
278 
279     if (nosoundfx)
280         return 0;
281 
282 #ifndef HAVE_MIXER
283     SDL_LockAudio();
284 #endif
285 
286     // Chainsaw troubles.
287     // Play these sound effects only one at a time.
288     if (S_sfx[sfxid].flags & SFX_single)
289     {
290         // Loop all channels, check.
291         for (i = 0; i < NUM_CHANNELS; i++)
292         {
293 	    chanp = & mix_channel[i];
294             // if Active, and using the same SFX
295 	    if ((chanp->data_ptr) && (chanp->sfxid == sfxid))
296             {
297 	        if( S_sfx[sfxid].flags & SFX_id_fin )
298 		    return chanp->handle;  // already have one
299                 // Kill, Reset.
300                 chanp->data_ptr = 0;
301                 break;
302             }
303         }
304     }
305 
306     // Loop all channels to find unused channel, or oldest SFX.
307     slot = 0;  // default
308     int oldest = -1;
309     for (i = 0; (i < NUM_CHANNELS); i++)
310     {
311         if (! mix_channel[i].data_ptr )  // unused
312         {
313 	    slot = i;
314 	    break;
315 	}
316         // handles sound_age wrap, by considering only diff
317         register unsigned int  agpr = sound_age - mix_channel[i].age_priority;
318         if (agpr > oldest)   // older
319         {
320             slot = i;
321             oldest = agpr;
322         }
323     }
324 
325     chanp = & mix_channel[slot];  // channel to use
326 
327     // Preserve sound SFX id,
328     //  e.g. for avoiding duplicates of chainsaw.
329     chanp->sfxid = sfxid;
330 
331     byte * header = S_sfx[sfxid].data;
332     // Okay, in the less recent channel,
333     //  we will handle the new SFX.
334     // Set pointer to raw data, skipping header.
335     chanp->data_ptr = (unsigned char *) S_sfx[sfxid].data + 8;
336 //    chanp->data_ptr = & header[8];
337     // Set pointer to end of raw data.
338     chanp->data_end = chanp->data_ptr + S_sfx[sfxid].length;
339 
340     // Get samplerate from the sfx header, 16 bit, big endian
341     chanp->samplerate = (header[3] << 8) + header[2];
342 
343     // Set stepping
344     chanp->step = steptable[pitch] * chanp->samplerate / DOOM_SAMPLERATE;
345     // 16.16 fixed point
346     chanp->step_remainder = 0;
347     // balanced between age and priority
348     // low priority (higher value) increases age
349     chanp->age_priority = sound_age - priority;  // age at start
350     sound_age += 16;  // vrs priority 0..256
351 
352     // Per left/right channel.
353     //  x^2 seperation,
354     //  adjust volume properly.
355     //    vol *= 8;
356 
357     // vol : range 0..255
358     // mix_sfxvolume : range 0..31
359     vol = (vol * mix_sfxvolume) >> 7;
360     // Notice : sdldoom replaced all the calls to avoid this conversion
361 
362     int leftvol, rightvol;
363 
364 #ifdef SURROUND_SOUND
365     chanp->invert_right = 0;
366     if( sep == SURROUND_SEP )
367     {
368         // Use a normal sound data for the left channel (with pan left)
369         // and an inverted sound data for the right channel (with pan right)
370         leftvol = rightvol = (vol * (224 * 224)) >> 16;  // slight reduction going through panning
371         chanp->invert_right = 1;  // invert right channel
372     }
373     else
374 #endif
375     {
376         // Separation, that is, orientation/stereo.
377         // sep : +/- 127, <0 is left, >0 is right
378         sep += 129;  // 129 +/- 127 ; ( 1 - 256 )
379         leftvol = vol - ((vol * sep * sep) >> 16);
380         sep = 258 - sep;  // 129 +/- 127
381         rightvol = vol - ((vol * sep * sep) >> 16);
382     }
383 
384     // Sanity check, clamp volume.
385     if (rightvol < 0 || rightvol > 127)
386     {
387         I_SoftError("rightvol out of bounds\n");
388         rightvol = ( rightvol < 0 ) ? 0 : 127;
389     }
390 
391     if (leftvol < 0 || leftvol > 127)
392     {
393         I_SoftError("leftvol out of bounds\n");
394         leftvol = ( leftvol < 0 ) ? 0 : 127;
395     }
396 
397     // Get the proper lookup table piece
398     //  for this volume level
399     chanp->leftvol_lookup = &vol_lookup[leftvol * 256];
400     chanp->rightvol_lookup = &vol_lookup[rightvol * 256];
401 
402     // Assign current handle number.
403     // Preserved so sounds could be stopped.
404     handle = slot | ((chanp->handle + NUM_CHANNELS) & ~CHANNEL_NUM_MASK);
405     chanp->handle = handle;
406 
407 #ifndef HAVE_MIXER
408     SDL_UnlockAudio();
409 #endif
410 
411     // Returns a handle
412     return handle;
413 }
414 
415 
416 //   handle : the handle returned by StartSound.
417 //  vol : volume, 0..255
418 //  sep : separation, +/- 127
I_UpdateSoundParams(int handle,int vol,int sep,int pitch)419 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
420 {
421     int slot = handle & CHANNEL_NUM_MASK;
422 
423     if( mix_channel[slot].handle == handle )
424     {
425         mix_channel_t  *  chanp = & mix_channel[slot];  // channel to use
426 
427         // Per left/right channel.
428         //  x^2 seperation,
429         //  adjust volume properly.
430         //    vol *= 8;
431         // vol : range 0..255
432         // mix_sfxvolume : range 0..31
433         vol = (vol * mix_sfxvolume) >> 7;
434 
435         int leftvol, rightvol;
436 
437 #ifdef SURROUND_SOUND
438         chanp->invert_right = 0;
439         if( sep == SURROUND_SEP )
440         {
441             // Use normal sound data for the left channel (pan left)
442             // and inverted sound data for the right channel (pan right).
443             leftvol = rightvol = (vol * (224 * 224)) >> 16;  // slight reduction going through panning
444             chanp->invert_right = 1;  // invert right channel
445         }
446         else
447 #endif
448         {
449             // Separation, that is, orientation/stereo.
450             // sep : +/- 127, <0 is left, >0 is right
451             sep += 129;  // 129 +/- 127 ; ( 1 - 256 )
452             leftvol = vol - ((vol * sep * sep) >> 16);
453             sep = 258 - sep;  // -129 +/- 127
454             rightvol = vol - ((vol * sep * sep) >> 16);
455         }
456 
457         // Sanity check, clamp volume.
458         if (rightvol < 0 || rightvol > 127)
459         {
460 	    I_SoftError("rightvol out of bounds\n");
461 	    rightvol = ( rightvol < 0 ) ? 0 : 127;
462 	}
463 
464         if (leftvol < 0 || leftvol > 127)
465         {
466 	    I_SoftError("leftvol out of bounds\n");
467 	    leftvol = ( leftvol < 0 ) ? 0 : 127;
468 	}
469 
470         // Get the proper lookup table piece
471         //  for this volume level
472         chanp->leftvol_lookup = &vol_lookup[leftvol * 256];
473         chanp->rightvol_lookup = &vol_lookup[rightvol * 256];
474 
475         // Set stepping
476 //        chanp->step = steptable[pitch];
477         chanp->step = steptable[pitch] * chanp->samplerate / DOOM_SAMPLERATE;
478     }
479 }
480 
481 
482 //   handle : the handle returned by StartSound.
I_StopSound(int handle)483 void I_StopSound(int handle)
484 {
485     int slot = handle & CHANNEL_NUM_MASK;
486     if( mix_channel[slot].handle == handle )
487     {
488         // outside caller should lock
489 #ifndef HAVE_MIXER
490         SDL_LockAudio();
491 #endif
492 
493         mix_channel[slot].data_ptr = NULL;
494 //        stop_channel( & mix_channel[slot] );
495 
496 #ifndef HAVE_MIXER
497         SDL_UnlockAudio();
498 #endif
499     }
500 }
501 
502 //   handle : the handle returned by StartSound.
I_SoundIsPlaying(int handle)503 int I_SoundIsPlaying(int handle)
504 {
505     int slot = handle & CHANNEL_NUM_MASK;
506     if( mix_channel[slot].handle == handle )
507     {
508         return mix_channel[slot].data_ptr != NULL;
509     }
510     return 0;
511 }
512 
513 //
514 // Not used by SDL version
515 //
I_SubmitSound(void)516 void I_SubmitSound(void)
517 {
518 }
519 
520 //
521 // This function loops all active (internal) sound
522 //  channels, retrieves a given number of samples
523 //  from the raw sound data, modifies it according
524 //  to the current (internal) channel parameters,
525 //  mixes the per channel samples into the given
526 //  mixing buffer, and clamping it to the allowed
527 //  range.
528 //
529 // This function currently supports only 16bit.
530 //
I_UpdateSound(void)531 void I_UpdateSound(void)
532 {
533     /*
534        Pour une raison que j'ignore, la version SDL n'appelle jamais
535        ce truc directement. Fonction vide pour garder une compatibilit�
536        avec le point de vue de legacy...
537      */
538 
539     // Himmel, Arsch und Zwirn
540 }
541 
I_UpdateSound_sdl(void * unused,Uint8 * stream,int len)542 static void I_UpdateSound_sdl(void *unused, Uint8 *stream, int len)
543 {
544     int chan;
545     // Mix current sound data.
546     // Data, from raw sound, for right and left.
547     if (nosoundfx)
548         return;
549 
550     // Pointers in audio stream, left, right, end.
551     // Left and right channels are multiplexed in the audio stream, alternating.
552     Sint16 *leftout  = (Sint16 *)stream;
553     Sint16 *rightout = leftout + 1;
554 
555     // Step in stream, left and right channels, thus two.
556     int step = 2;
557 
558     // first Sint16 at least partially outside the buffer
559     Sint16 *buffer_end = ((Sint16 *)stream) +len/sizeof(Sint16);
560 
561     // Mix sounds into the mixing buffer.
562     while (rightout < buffer_end)
563     {
564         // take the current audio output (incl. music) and mix (add) in our sfx
565         register int dl = *leftout;
566         register int dr = *rightout;
567 
568         // Love thy L2 chache - made this a loop.
569         // Now more channels could be set at compile time
570         //  as well. Thus loop those  channels.
571 	// Mixing channel index.
572         register mix_channel_t * chanp = & mix_channel[ 0 ];
573         for (chan = NUM_CHANNELS; chan > 0; chan--)
574         {
575 	    register byte * chan_data_ptr = chanp->data_ptr;
576             // Check channel, if active.
577             if ( chan_data_ptr )
578             {
579 	        // Get the raw data from the channel.
580 	        register unsigned int sample = * chan_data_ptr;
581                 // Add left and right part for this channel (sound)
582                 //  to the current data.
583                 // Adjust volume accordingly.
584                 dl += chanp->leftvol_lookup[sample];
585 #ifdef SURROUND_SOUND
586                 if( chanp->invert_right )
587                   dr -= chanp->rightvol_lookup[sample];
588                 else
589                   dr += chanp->rightvol_lookup[sample];
590 #else
591                 dr += chanp->rightvol_lookup[sample];
592 #endif
593 		// 16.16 fixed point step forward in the sound data
594                 chanp->step_remainder += chanp->step;
595                 // take full steps
596                 chan_data_ptr += chanp->step_remainder >> 16;
597                 // remainder, save for next round
598                 chanp->step_remainder &= 0xFFFF;
599 
600                 // Check whether we are done.
601                 if (chan_data_ptr >= chanp->data_end)
602                     chan_data_ptr = NULL;
603 
604 	        chanp->data_ptr = chan_data_ptr;
605             }
606 	    chanp ++;  // next channel
607         }
608 
609         // Clamp to range. Left hardware channel.
610         // Has been char instead of short.
611 
612         if (dl > 0x7fff)
613             *leftout = 0x7fff;
614         else if (dl < -0x8000)
615             *leftout = -0x8000;
616         else
617             *leftout = dl;
618 
619         // Same for right hardware channel.
620         if (dr > 0x7fff)
621             *rightout = 0x7fff;
622         else if (dr < -0x8000)
623             *rightout = -0x8000;
624         else
625             *rightout = dr;
626 
627         // Increment current pointers in stream
628         leftout += step;
629         rightout += step;
630     }
631 }
632 
633 
634 
635 
636 //
637 // MUSIC API.
638 //
639 
640 #ifdef HAVE_MIXER
641 /// the "registered" piece of music
642 static struct music_channel_t
643 {
644   Mix_Music *mus;
645   SDL_RWops *rwop; ///< must not be freed before music is halted
646 } music = { NULL, NULL };
647 
648 
649 #if ((SDL_MIXER_MAJOR_VERSION*100)+(SDL_MIXER_MINOR_VERSION*10)+SDL_MIXER_PATCHLEVEL) < 127
650   // Older SDL without RWOPS
651 #define OLD_SDL_MIXER
652 
653 #ifdef SMIF_PC_DOS
654 static char * midiname = "DoomMUS.mid";
655 #else
656 static char midiname[24] = "/tmp/DoomMUSXXXXXX";
657 #endif
658 FILE * midifile;
659 
Init_OLD_SDL_MIXER(void)660 void Init_OLD_SDL_MIXER( void )
661 {
662 #ifndef SMIF_PC_DOS
663     // Make temp file name
664     mkstemp( midiname );
665 //    strcat( midiname, ".mid" );
666 #endif
667 //    fprintf( stderr, "Midiname= %s\n", midiname );
668 }
669 
Free_OLD_SDL_MIXER(void)670 void Free_OLD_SDL_MIXER( void )
671 {
672     // delete the temp file
673     remove( midiname );
674 }
675 
676 
677 #include <errno.h>
678 extern int errno;
679 
Midifile_OLD_SDL_MIXER(byte * midibuf,unsigned long midilength)680 void Midifile_OLD_SDL_MIXER( byte* midibuf, unsigned long midilength )
681 {
682     midifile = fopen( midiname, "wb" );
683     if( midifile )
684     {
685 	  fwrite( midibuf, midilength, 1, midifile );
686 	  fclose( midifile );
687           if(verbose)
688               fprintf( stderr, "Midifile written: %s size=%li\n", midiname, midilength );
689 
690           // wants file to have .MID extension, but mkstemp file cannot have extension
691 	  music.mus = Mix_LoadMUS( midiname );
692           if( music.mus == NULL )
693           {
694 	     I_SoftError("Music load file failed\n");
695 	     perror( "Mix_LoadMUS fails when not cd to doomlegacy directory" );
696 	  }
697     }
698 }
699 #endif
700 #endif
701 
702 
I_PlaySong(int handle,byte looping)703 void I_PlaySong(int handle, byte looping)
704 {
705 #ifdef HAVE_MIXER
706   if (nomusic)
707     return;
708 
709   if (music.mus)
710   {
711       Mix_FadeInMusic(music.mus, looping ? -1 : 1, MUSIC_FADE_TIME);
712   }
713 #endif
714 }
715 
I_PauseSong(int handle)716 void I_PauseSong(int handle)
717 {
718 #ifdef HAVE_MIXER
719   if (nomusic)
720     return;
721 
722   Mix_PauseMusic();
723 #endif
724 }
725 
I_ResumeSong(int handle)726 void I_ResumeSong(int handle)
727 {
728 #ifdef HAVE_MIXER
729   if (nomusic)
730     return;
731 
732   Mix_ResumeMusic();
733 #endif
734 }
735 
I_StopSong(int handle)736 void I_StopSong(int handle)
737 {
738 #ifdef HAVE_MIXER
739   if (nomusic)
740     return;
741 
742   Mix_FadeOutMusic(MUSIC_FADE_TIME);
743 #endif
744 }
745 
746 
I_UnRegisterSong(int handle)747 void I_UnRegisterSong(int handle)
748 {
749 #ifdef HAVE_MIXER
750   if (nomusic)
751     return;
752 
753   if (music.mus)
754   {
755       Mix_FreeMusic(music.mus);
756       music.mus = NULL;
757       music.rwop = NULL;
758   }
759 #endif
760 }
761 
762 
763 // return handle (always 0)
764 //  data : ptr to lump data
765 //  len : length of data
I_RegisterSong(void * data,int len)766 int I_RegisterSong( void* data, int len )
767 {
768 #ifdef HAVE_MIXER
769   if (nomusic)
770     return 0;
771 
772   if (music.mus)
773   {
774       I_SoftError("Two registered pieces of music simultaneously!\n");
775       return 0;
776   }
777 
778   if (memcmp(data, MUSHEADER, 4) == 0)
779   {
780       unsigned long midilength;  // per qmus2mid, SDL_RWFromConstMem wants int
781       // convert mus to mid in memory with a wonderful function
782       // thanks to S.Bacquet for the source of qmus2mid
783       int err = qmus2mid(data, len, 89, 0, MIDBUFFERSIZE,
784                /*INOUT*/ midi_buffer, &midilength);
785       if ( err != QM_success )
786       {
787 	  I_SoftError("Cannot convert MUS to MIDI: error %d.\n", err);
788 	  return 0;
789       }
790 #ifdef OLD_SDL_MIXER
791       Midifile_OLD_SDL_MIXER( midi_buffer, midilength );
792 #else
793       music.rwop = SDL_RWFromConstMem(midi_buffer, midilength);
794 #endif
795   }
796   else
797   {
798       // MIDI, MP3, Ogg Vorbis, various module formats
799 #ifdef OLD_SDL_MIXER
800       Midifile_OLD_SDL_MIXER( data, len );
801 #else
802       music.rwop = SDL_RWFromConstMem(data, len);
803 #endif
804   }
805 
806 #ifdef OLD_SDL_MIXER
807   // In old mixer Mix_LoadMUS_RW does not work.
808 #else
809   // SDL_mixer automatically frees the rwop when the music is stopped.
810   music.mus = Mix_LoadMUS_RW(music.rwop);
811 #endif
812   if (!music.mus)
813   {
814       I_SoftError("Couldn't load music lump: %s\n", Mix_GetError());
815       music.rwop = NULL;
816   }
817 
818 //  debug_Printf("register song\n"); 	// [WDJ] debug
819 #endif
820 
821   return 0;
822 }
823 
824 
I_SetMusicVolume(int volume)825 void I_SetMusicVolume(int volume)
826 {
827   // volume: 0--31
828 #ifdef HAVE_MIXER
829   if (nomusic)
830     return;
831 
832   Mix_VolumeMusic((MIX_MAX_VOLUME * volume) / 32);
833 #endif
834 }
835 
836 
837 
838 
I_StartupSound(void)839 void I_StartupSound(void)
840 {
841   static SDL_AudioSpec audspec;  // [WDJ] desc name, too many audio in this file
842 
843   if( nosoundfx )
844   {
845       nomusic = true;
846       return;
847   }
848 
849   // Configure sound device
850   CONS_Printf("I_InitSound: ");
851 
852   // Open the audio device
853   audspec.freq = SAMPLERATE;
854   audspec.format = AUDIO_S16SYS;
855   audspec.channels = 2;
856   // From eternity, adjust for new samplerate
857   audspec.samples = SAMPLECOUNT * SAMPLERATE / DOOM_SAMPLERATE;
858   audspec.callback = I_UpdateSound_sdl;
859   I_SetChannels();
860 
861 #ifndef HAVE_MIXER
862   // no mixer, no music
863   nomusic = true;
864 
865   // Open the audio device
866   if (SDL_OpenAudio(&audspec, NULL) < 0)
867   {
868       CONS_Printf("Couldn't open audio with desired format.\n");
869       SDL_CloseAudio();
870       nosoundfx = nomusic = true;
871       return;
872   }
873 
874   SDL_PauseAudio(0);
875 #else
876   // use SDL_mixer for music
877 
878   // because we use SDL_mixer, audio is opened here.
879   if (Mix_OpenAudio(audspec.freq, audspec.format, audspec.channels, audspec.samples) < 0)
880   {
881     // [WDJ] On sound cards without midi ports, opening audio will block music.
882     // When midi music is played through Timidity, it will also try to use the
883     // dsp port, which is already in use.  Need to use a mixer on sound
884     // effect and Timidity output.  Some sound cards have two dsp ports.
885 
886         CONS_Printf("Unable to open audio: %s\n", Mix_GetError());
887         nosoundfx = nomusic = true;
888         return;
889   }
890 
891   int number_channels;	// for QuerySpec
892   if (!Mix_QuerySpec(&audspec.freq, &audspec.format, &number_channels))
893   {
894       CONS_Printf("Mix_QuerySpec: %s\n", Mix_GetError());
895       nosoundfx = nomusic = true;
896       return;
897   }
898 
899   Mix_SetPostMix(audspec.callback, NULL);  // after mixing music, add sound fx
900   Mix_Resume(-1); // start all sound channels (although they are not used)
901 #endif
902 
903   CONS_Printf("Audio device initialized: %d Hz, %d samples/slice.\n",
904 	      audspec.freq, audspec.samples);
905 
906 #ifdef HAVE_MIXER
907   if (!nomusic)
908   {
909       Mix_ResumeMusic();  // start music playback
910       midi_buffer = (byte *)Z_Malloc(MIDBUFFERSIZE, PU_STATIC, NULL);
911 
912 #ifdef OLD_SDL_MIXER
913   Init_OLD_SDL_MIXER();
914 #endif
915 
916       CONS_Printf(" Music initialized.\n");
917       musicStarted = true;
918   }
919 #endif
920 
921   // Finished initialization.
922   CONS_Printf("I_InitSound: sound module ready.\n");
923   soundStarted = true;
924 
925   CONS_Printf(" done.\n");
926 }
927 
928 
I_ShutdownSound(void)929 void I_ShutdownSound(void)
930 {
931   if (nosoundfx || !soundStarted)
932     return;
933 
934   CONS_Printf("I_ShutdownSound: ");
935 
936 #ifdef HAVE_MIXER
937   Mix_CloseAudio();
938 #else
939   SDL_CloseAudio();
940 #endif
941 
942   CONS_Printf("shut down\n");
943   soundStarted = false;
944 
945   // music
946   if (musicStarted)
947   {
948       Z_Free(midi_buffer);
949 
950 #ifdef OLD_SDL_MIXER
951       Free_OLD_SDL_MIXER();
952 #endif
953 
954       musicStarted = false;
955   }
956 }
957