5 #include <math.h> // pow()
10 #include "audio_plugin.h"
13 #define SAMPLE_FORMAT FMT_S16_LE
15 #define SAMPLE_RATE 11025 // Hz
16 #define SAMPLE_CHANNELS 2
19 #define SAMPLE_TYPE char
21 #define SAMPLE_TYPE short
35 const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
39 int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
40 int snd_MusicDevice, // current music card # (index to dmxCodes)
41 snd_SfxDevice, // current sfx card # (index to dmxCodes)
42 snd_MaxVolume, // maximum volume for sound
43 snd_MusicVolume; // maximum volume for music
44 int dmxCodes[NUM_SCARDS]; // the dmx code for a given card
46 int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
47 int snd_Mport; // midi variables
49 extern boolean snd_MusicAvail, // whether music is available
50 snd_SfxAvail; // whether sfx are available
52 // Function prototypes (if needed) - DDOI
53 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
55 void I_PauseSong(int handle)
59 void I_ResumeSong(int handle)
63 void I_SetMusicVolume(int volume)
67 void I_SetSfxVolume(int volume)
77 int I_RegisterSong(void *data)
82 void I_UnRegisterSong(int handle)
86 int I_QrySongPlaying(int handle)
91 // Stops a song. MUST be called before I_UnregisterSong().
93 void I_StopSong(int handle)
97 void I_PlaySong(int handle, boolean looping)
110 unsigned char* begin; // pointers into Sample.firstSample
113 SAMPLE_TYPE* lvol_table; // point into vol_lookup
114 SAMPLE_TYPE* rvol_table;
116 unsigned int pitch_step;
117 unsigned int step_remainder; // 0.16 bit remainder of last step.
127 short freq; // always 11025
128 long length; // sample length
129 unsigned char firstSample;
133 extern OutputPlugin* get_oplugin_info();
134 static OutputPlugin* audioPI = 0;
135 static int audio_exit_thread = 1;
136 static pthread_t audio_thread;
140 Channel channel[ CHAN_COUNT ];
142 #define MAX_VOL 64 // 64 keeps our table down to 16Kb
143 SAMPLE_TYPE vol_lookup[ MAX_VOL * 256 ];
145 int steptable[ 256 ]; // Pitch to stepping lookup
148 #define BUF_LEN 256*2
151 void* audio_loop( void* arg )
163 end = (SAMPLE_TYPE*) (buf + BUF_LEN);
164 cend = channel + CHAN_COUNT;
166 while( ! audio_exit_thread )
168 begin = (SAMPLE_TYPE*) buf;
171 // Mix all the channels together.
177 for( ; chan < cend; chan++ )
179 // Check channel, if active.
182 // Get the sample from the channel.
183 sample = *chan->begin;
185 // Adjust volume accordingly.
186 dl += chan->lvol_table[ sample ];
187 dr += chan->rvol_table[ sample ];
189 // Increment sample pointer with pitch adjustment.
190 chan->step_remainder += chan->pitch_step;
191 chan->begin += chan->step_remainder >> 16;
192 chan->step_remainder &= 65535;
194 // Check whether we are done.
195 if( chan->begin >= chan->end )
198 //printf( " channel done %d\n", chan );
203 #if 0 //SAMPLE_FORMAT
204 if( dl > 127 ) dl = 127;
205 else if( dl < -128 ) dl = -128;
207 if( dr > 127 ) dr = 127;
208 else if( dr < -128 ) dr = -128;
210 if( dl > 0x7fff ) dl = 0x7fff;
211 else if( dl < -0x8000 ) dl = -0x8000;
213 if( dr > 0x7fff ) dr = 0x7fff;
214 else if( dr < -0x8000 ) dr = -0x8000;
221 // This write is expected to block.
222 audioPI->write_audio( buf, BUF_LEN );
229 // Gets lump nums of the named sound. Returns pointer which will be
230 // passed to I_StartSound() when you want to start an SFX. Must be
231 // sure to pass this to UngetSoundEffect() so that they can be
235 int I_GetSfxLumpNum(sfxinfo_t *sound)
237 // char namebuf[9]; // unused variable - DDOI
239 if (sound->name == 0)
241 if(sound->link) sound = sound->link;
242 return W_GetNumForName(sound->name);
247 // Data is a pointer to a Sample structure.
248 // Volume ranges from 0 to 127.
249 // Separation (orientation/stereo) ranges from 0 to 255. 128 is balanced.
250 // Pitch ranges from 0 to 255. Normal is 128.
251 // Priority looks to be unused (always 0).
253 int I_StartSound( int id, void* data, int vol, int sep, int pitch, int priority)
255 // Relative time order to find oldest sound.
256 static unsigned int soundTime = 0;
264 // Find an empty channel, the oldest playing channel, or default to 0.
265 // Currently ignoring priority.
269 for( i = 0; i < CHAN_COUNT; i++ )
271 if( ! channel[ i ].begin )
276 if( channel[ i ].time < oldest )
279 oldest = channel[ i ].time;
283 sample = (Sample*) data;
284 chan = &channel[ chanId ];
286 I_UpdateSoundParams( chanId + 1, vol, sep, pitch );
288 // begin must be set last because the audio thread will access the channel
289 // once it is non-zero. Perhaps this should be protected by a mutex.
291 chan->pri = priority;
292 chan->time = soundTime;
293 chan->end = &sample->firstSample + sample->length;
294 chan->begin = &sample->firstSample;
299 printf( "I_StartSound %d: v:%d s:%d p:%d pri:%d | %d %d %d %d\n",
300 id, vol, sep, pitch, priority,
301 chanId, chan->pitch_step, sample->a, sample->freq );
307 void I_StopSound(int handle)
311 channel[ handle ].begin = 0;
314 int I_SoundIsPlaying(int handle)
318 return( channel[ handle ].begin != 0 );
321 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
326 // Set left/right channel volume based on seperation.
328 sep += 1; // range 1 - 256
329 lvol = vol - ((vol * sep * sep) >> 16); // (256*256);
331 rvol = vol - ((vol * sep * sep) >> 16);
334 // Sanity check, clamp volume.
337 //printf( "rvol out of bounds %d, id %d\n", rvol, handle );
340 else if( rvol > 127 )
342 //printf( "rvol out of bounds %d, id %d\n", rvol, handle );
348 //printf( "lvol out of bounds %d, id %d\n", lvol, handle );
351 else if( lvol > 127 )
353 //printf( "lvol out of bounds %d, id %d\n", lvol, handle );
357 // Limit to MAX_VOL (64)
363 chan = &channel[ handle ];
364 chan->pitch_step = steptable[ pitch ];
365 chan->step_remainder = 0;
366 chan->lvol_table = &vol_lookup[ lvol * 256 ];
367 chan->rvol_table = &vol_lookup[ rvol * 256 ];
372 * SOUND STARTUP STUFF
377 // inits all sound stuff
379 void I_StartupSound (void)
383 snd_MusicDevice = snd_SfxDevice = 0;
385 if( M_CheckParm( "-nosound" ) )
387 tprintf("I_StartupSound: Sound Disabled.\n",1);
392 tprintf("I_StartupSound: Hope you hear a pop.\n",1);
394 /* Using get_oplugin_info() from oss.c. In the future this could
395 load from a real shared library plugin. */
396 audioPI = get_oplugin_info();
400 ok = audioPI->open_audio( SAMPLE_FORMAT, SAMPLE_RATE, SAMPLE_CHANNELS );
403 audio_exit_thread = 0;
404 pthread_create( &audio_thread, NULL, audio_loop, NULL);
408 fprintf( stderr, "I_StartupSound: failed\n" );
412 // shuts down all sound stuff
414 void I_ShutdownSound (void)
418 if( ! audio_exit_thread )
420 audio_exit_thread = 1;
421 pthread_join( audio_thread, NULL );
423 audioPI->close_audio();
427 void I_SetChannels(int channels)
432 // We always have CHAN_COUNT channels.
434 for( j = 0; j < CHAN_COUNT; j++ )
436 channel[ j ].begin = 0;
437 channel[ j ].end = 0;
438 channel[ j ].time = 0;
442 // This table provides step widths for pitch parameters.
443 steptablemid = steptable + 128;
444 for( j = -128; j < 128; j++ )
446 steptablemid[ j ] = (int) (pow( 2.0, (j/64.0) ) * 65536.0);
450 // Generate the volume lookup tables.
451 for( v = 0 ; v < MAX_VOL ; v++ )
453 for( j = 0; j < 256; j++ )
455 //vol_lookup[v*256+j] = 128 + ((v * (j-128)) / (MAX_VOL-1));
457 // Turn the unsigned samples into signed samples.
458 #if 0 // SAMPLE_FORMAT
459 vol_lookup[v*256+j] = (v * (j-128)) / (MAX_VOL-1);
461 vol_lookup[v*256+j] = (v * (j-128) * 256) / (MAX_VOL-1);
464 //printf("vol_lookup[%d*256+%d] = %d\n", v, j, vol_lookup[v*256+j]);