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