1 #include <stdio.h>
2 #include <math.h>       // pow()
3 #include <SDL.h>
4 #include <SDL_mixer.h>
5 #include "qmus2mid.h"
6 #include "h2def.h"
7 #include "sounds.h"
8 #include "i_sound.h"
9 
10 extern char *SavePath;
11 Mix_Music *CurrentSong;
12 int SongPlaying;
13 int audio_opened;
14 
15 
16 #define SAMPLE_TYPE     short
17 
18 
19 /*
20  *
21  *                           SOUND HEADER & DATA
22  *
23  *
24  */
25 
26 int tsm_ID = -1;
27 
28 const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
29   'M', 'M', 'S' };
30 
31 int snd_Channels;
32 int	snd_MaxVolume;      // maximum volume for sound
33 int	snd_MusicVolume;    // maximum volume for music
34 
35 
36 void Postmix(void *userdata, Uint8 *stream, int len);
37 
au_close(void)38 void au_close(void)
39 {
40  Mix_CloseAudio();
41 }
42 
au_open(void)43 int au_open(void)
44 {
45  int ret;
46 
47  ret=Mix_OpenAudio(11025,AUDIO_S16LSB,2,512);
48  if (ret>=0) {
49   printf("SDL Audio opened successfully.\n");
50   Mix_SetPostMix(Postmix,NULL);
51   SongPlaying=0;
52   audio_opened=1;
53   return 1;
54  }
55  return 0;
56 }
57 
I_PauseSong(int handle)58 void I_PauseSong(int handle)
59 {
60  Mix_PauseMusic();
61 }
62 
I_ResumeSong(int handle)63 
64 void I_ResumeSong(int handle)
65 {
66   Mix_ResumeMusic();
67 }
I_SetMusicVolume(int volume)68 
69 void I_SetMusicVolume(int volume)
70 {
71  Mix_VolumeMusic(volume*8);
72 }
I_SetSfxVolume(int volume)73 
74 void I_SetSfxVolume(int volume)
75 {
76 }
77 
78 /*
79  *
80  *                              SONG API
81  *
82  */
I_RegisterSong(void * data,int size)83 
84 int I_RegisterSong(void *data, int size)
85 {
86   FILE *f;
87   int sl;
88 #ifndef MUSTDIE
89   char *fn="/CurrentSong.mid";
90 #else
91   char *fn="\\CURSONG.MID";
92 #endif
93   char *SongPath;
94 
95   if (SongPlaying) {
96    I_StopSong(0);
97    SDL_Delay(20);
98    I_UnRegisterSong(0);
99   }
100 
101   sl=strlen(SavePath);
102   SongPath=malloc(sl+strlen(fn)+1);
103   strcpy(SongPath,SavePath);
104   strcat(SongPath,fn);
105   f=fopen(SongPath,"wb");
106   if (!audio_opened)
107    au_open();
108   if (f) {
109    qmus2mid(data,size,f,1,0,0,0);
110    fclose(f);
111    CurrentSong=Mix_LoadMUS(SongPath);
112    if (!CurrentSong) {
113      printf("MIDI load failed:%s\n",Mix_GetError());
114    }
115   }
116   free(SongPath);
117   return 0;
118 }
I_UnRegisterSong(int handle)119 
120 void I_UnRegisterSong(int handle)
121 {
122   if (CurrentSong) {
123    Mix_FreeMusic(CurrentSong);
124    CurrentSong=NULL;
125   }
126 }
I_QrySongPlaying(int handle)127 
128 int I_QrySongPlaying(int handle)
129 {
130  return SongPlaying;
131  /* XXX */
132 }
133 
I_StopSong(int handle)134 // Stops a song.  MUST be called before I_UnregisterSong().
135 
136 void I_StopSong(int handle)
137 {
138   Mix_FadeOutMusic(500);
139   SongPlaying=0;
140 }
141 
142 
143 void I_PlaySong(int handle, boolean looping)
144 {
145  if (SongPlaying) return;
146  Mix_FadeInMusic(CurrentSong,looping?-1:0,500);
147  SongPlaying=1;
148 }
149 
150 
151 
152 /*
153  *
154  *                                 SOUND FX API
155  *
156  */
157 
158 
159 typedef struct
160 {
161     unsigned char* begin;           // pointers into Sample.firstSample
162     unsigned char* end;
163 
164     SAMPLE_TYPE* lvol_table;               // point into vol_lookup
165     SAMPLE_TYPE* rvol_table;
166 
167     unsigned int pitch_step;
168     unsigned int step_remainder;    // 0.16 bit remainder of last step.
169 
170     int pri;
171     unsigned int time;
172 } Channel;
173 
174 
175 typedef struct
176 {
177     short a;            // always 3
178     short freq;         // always 11025
179     long length;        // sample length
180     unsigned char firstSample;
181 } Sample;
182 
183 
184 #define CHAN_COUNT        8
185 Channel schannel[ CHAN_COUNT];
186 
187 #define MAX_VOL           64        // 64 keeps our table down to 16Kb
188 SAMPLE_TYPE vol_lookup[ MAX_VOL * 256 ];
Postmix(void * userdata,Uint8 * stream,int len)189 
190 int steptable[ 256 ];               // Pitch to stepping lookup
191 
192 
193 void Postmix(void *userdata, Uint8 *stream, int len)
194 {
195     Channel* chan;
196     Channel* cend;
197     SAMPLE_TYPE* begin;
198     SAMPLE_TYPE* end;
199     unsigned int sample;
200     register int dl;
201     register int dr;
202 
203     end = (SAMPLE_TYPE*) (stream + len);
204     cend = schannel + CHAN_COUNT;
205 
206     begin = (SAMPLE_TYPE*) stream;
207     while( begin < end )
208         {
209             // Mix all the channels together.
210 
211             dl = 0;
212   /* zero sample */
213             dr = 0;
214             chan = schannel;
215             for( ; chan < cend; chan++ )
216             {
217                 // Check channel, if active.
218                 if( chan->begin )
219                 {
220                     // Get the sample from the channel.
221                     sample = *chan->begin;
222 
223                     // Adjust volume accordingly.
224                     dl += chan->lvol_table[ sample ];
225                     dr += chan->rvol_table[ sample ];
226 
227                     // Increment sample pointer with pitch adjustment.
228                     chan->step_remainder += chan->pitch_step;
229                     chan->begin += chan->step_remainder >> 16;
230                     chan->step_remainder &= 65535;
231 
232                     // Check whether we are done.
233                     if( chan->begin >= chan->end )
234                     {
235                         chan->begin = 0;
236                     }
237                 }
238             }
239 
240             if( dl > 0x7fff ) dl = 0x7fff;
241             else if( dl < -0x8000 ) dl = -0x8000;
242 
243             if( dr > 0x7fff ) dr = 0x7fff;
244             else if( dr < -0x8000 ) dr = -0x8000;
245 
246 
247 	    sample=*begin + dl;
248             *begin++ = sample/2;
249 	    sample=*begin + dl;
250             *begin++ = sample/2;
251         }
252 
253 }
254 
255 
I_GetSfxLumpNum(sfxinfo_t * sound)256 // Gets lump nums of the named sound.  Returns pointer which will be
257 // passed to I_StartSound() when you want to start an SFX.  Must be
258 // sure to pass this to UngetSoundEffect() so that they can be
259 // freed!
260 
261 
262 int I_GetSfxLumpNum(sfxinfo_t *sound)
263 {
264   return W_GetNumForName(sound->lumpname);
265 }
266 
267 
268 // Id is unused.
I_StartSound(int id,void * data,int vol,int sep,int pitch,int priority)269 // Data is a pointer to a Sample structure.
270 // Volume ranges from 0 to 127.
271 // Separation (orientation/stereo) ranges from 0 to 255.  128 is balanced.
272 // Pitch ranges from 0 to 255.  Normal is 128.
273 // Priority looks to be unused (always 0).
274 
275 int I_StartSound( int id, void* data, int vol, int sep, int pitch, int priority)
276 {
277     // Relative time order to find oldest sound.
278     static unsigned int soundTime = 0;
279     int chanId;
280     Sample* sample;
281     Channel* chan;
282     int oldest;
283     int i;
284     // Find an empty channel, the oldest playing channel, or default to 0.
285     // Currently ignoring priority.
286 
287     chanId = 0;
288     oldest = soundTime;
289     for( i = 0; i < CHAN_COUNT; i++ )
290     {
291         if( ! schannel[ i ].begin )
292         {
293             chanId = i;
294             break;
295         }
296         if( schannel[ i ].time < oldest )
297         {
298             chanId = i;
299             oldest = schannel[ i ].time;
300         }
301     }
302 
303     sample = (Sample*) data;
304     chan = &schannel[ chanId ];
305 
306     I_UpdateSoundParams( chanId + 1, vol, sep, pitch );
307 
308     chan->pri = priority;
309     chan->time = soundTime;
310     chan->end = &sample->firstSample + sample->length;
311     chan->begin = &sample->firstSample;
312 
313     soundTime++;
314 
315     return chanId + 1;
316 }
317 
318 void I_StopSound(int handle)
I_SoundIsPlaying(int handle)319 {
320     handle--;
321     handle &= 7;
322     schannel[ handle ].begin = 0;
323 }
324 
325 int I_SoundIsPlaying(int handle)
I_UpdateSoundParams(int handle,int vol,int sep,int pitch)326 {
327     handle--;
328     handle &= 7;
329     return( schannel[ handle ].begin != 0 );
330 }
331 
332 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
333 {
334     int lvol, rvol;
335     Channel* chan;
336 
337     // Set left/right channel volume based on seperation.
338 
339     sep += 1;       // range 1 - 256
340     lvol = vol - ((vol * sep * sep) >> 16); // (256*256);
341     sep = sep - 257;
342     rvol = vol - ((vol * sep * sep) >> 16);
343 
344 
345     // Sanity check, clamp volume.
346     if( rvol < 0 )
347     {
348         //printf( "rvol out of bounds %d, id %d\n", rvol, handle );
349         rvol = 0;
350     }
351     else if( rvol > 127 )
352     {
353         //printf( "rvol out of bounds %d, id %d\n", rvol, handle );
354         rvol = 127;
355     }
356 
357     if( lvol < 0 )
358     {
359         //printf( "lvol out of bounds %d, id %d\n", lvol, handle );
360         lvol = 0;
361     }
362     else if( lvol > 127 )
363     {
364         //printf( "lvol out of bounds %d, id %d\n", lvol, handle );
365         lvol = 127;
366     }
367 
368     // Limit to MAX_VOL (64)
369     lvol >>= 1;
370     rvol >>= 1;
371 
372     handle--;
373     handle &= 7;
374     chan = &schannel[ handle ];
375     chan->pitch_step = steptable[ pitch ];
376     chan->step_remainder = 0;
377     chan->lvol_table = &vol_lookup[ lvol * 256 ];
378     chan->rvol_table = &vol_lookup[ rvol * 256 ];
379 }
380 
381 /*
382  *
383  *                                                      SOUND STARTUP STUFF
I_StartupSound(void)384  *
385  *
386  */
387 
388 // inits all sound stuff
389 
390 void I_StartupSound (void)
391 {
392     int ok;
393 
394 //    snd_MusicDevice = snd_SfxDevice = 0;
395 
396     if( M_CheckParm( "-nosound" ) )
397     {
398         ST_Message("I_StartupSound: Sound Disabled.\n");
399         return;
400     }
401 
402     if (debugmode)
403         ST_Message("I_StartupSound: Hope you hear a pop.\n");
404 
405     if (!audio_opened)
406      ok = au_open();
407 
408 }
409 
410 // shuts down all sound stuff
411 
412 void I_ShutdownSound (void)
I_SetChannels(int channels)413 {
414 	I_StopSong(0);
415 	I_UnRegisterSong(0);
416         au_close();
417 }
418 
419 void I_SetChannels(int channels)
420 {
421     int v, j;
422     int* steptablemid;
423 
424     // We always have CHAN_COUNT channels.
425 
426     for( j = 0; j < CHAN_COUNT; j++ )
427     {
428         schannel[ j ].begin = 0;
429         schannel[ j ].end = 0;
430         schannel[ j ].time = 0;
431     }
432 
433 
434     // This table provides step widths for pitch parameters.
435     steptablemid = steptable + 128;
436     for( j = -128; j < 128; j++ )
437     {
438         steptablemid[ j ] = (int) (pow( 2.0, (j/64.0) ) * 65536.0);
439     }
440 
441 
442     // Generate the volume lookup tables.
443     for( v = 0 ; v < MAX_VOL ; v++ )
444     {
445         for( j = 0; j < 256; j++ )
446         {
447             //vol_lookup[v*256+j] = 128 + ((v * (j-128)) / (MAX_VOL-1));
448 
449             // Turn the unsigned samples into signed samples.
450             vol_lookup[v*256+j] = (v * (j-128) * 256) / (MAX_VOL-1);
451 
452             //printf("vol_lookup[%d*256+%d] = %d\n", v, j, vol_lookup[v*256+j]);
453         }
454     }
455 }
456 
457 
458 /* EOF */
459