mirror of
https://github.com/deater/tb1.git
synced 2024-10-27 14:26:51 +00:00
714 lines
18 KiB
C
714 lines
18 KiB
C
|
|
||
|
/* SoundIt library 0.04
|
||
|
|
||
|
Copyright 1994 Brad Pitzel pitzel@cs.sfu.ca
|
||
|
|
||
|
Adapted to Solaris/SunOS and HPUX by Peter Ekberg.
|
||
|
|
||
|
Feel free to use/distribute/modify as long as proper credits
|
||
|
are included.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
# include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#if defined(HAVE_LINUX_SOUND)
|
||
|
# include <linux/soundcard.h>
|
||
|
|
||
|
#elif defined(HAVE_SUN_SOUND)
|
||
|
# if defined(HAVE_SYS_AUDIOIO_H)
|
||
|
# include <sys/audioio.h>
|
||
|
# elif defined(HAVE_SUN_AUDIOIO_H)
|
||
|
# include <sun/audioio.h>
|
||
|
# endif
|
||
|
|
||
|
#elif defined(HAVE_HP_SOUND)
|
||
|
# include <sys/audio.h>
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#include "soundIt.h"
|
||
|
#include <malloc.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/wait.h>
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
/* the mix buff, where the channels are mixed into. The mix buffer is then
|
||
|
dumped to the sound device (/dev/dsp). Samples are mixed in
|
||
|
Vunclipbuf (buffer of ints), then the values in Vunclipbuf are clipped to
|
||
|
values between 0 and 255, and stored into Vclippedbuf (buffer of unsigned
|
||
|
chars).
|
||
|
*/
|
||
|
|
||
|
typedef struct {
|
||
|
#if defined(HAVE_LINUX_SOUND)
|
||
|
unsigned char *Vclippedbuf;
|
||
|
#elif defined(HAVE_16BIT_SOUND)
|
||
|
short *Vclippedbuf;
|
||
|
#endif
|
||
|
int *Vunclipbuf;
|
||
|
int Vsize;
|
||
|
} Mix;
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
typedef struct {
|
||
|
unsigned char *Vstart, *Vcurrent; /* ptr's into a playing sample */
|
||
|
int Vlen; /* length of sample in bytes */
|
||
|
int Vleft; /* bytes left of sample to play */
|
||
|
int Vloop; /* loop=0 : play sample once */
|
||
|
/* loop=1 : loop sample */
|
||
|
} Channel;
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
|
||
|
/* variables prefixed with S_ are static */
|
||
|
/* 0 if mixer isn't initialized or init failed, 1 if mixer is good */
|
||
|
static int S_mixerStatus = 0;
|
||
|
|
||
|
static const Sample *S_sounds = NULL; /* ptr to array of samples */
|
||
|
static int S_num_sounds = 0; /* size of 'sounds' array above */
|
||
|
static int S_fd_snddev = -1; /* file # for sound device once open */
|
||
|
static int S_fd_pipe[2] = { -1, -1 }; /* pipe to talk to child process */
|
||
|
static int S_son_pid = -1; /* process ID for the forked sound mixer */
|
||
|
static const char *S_snddev = NULL; /* char string for device, ie "/dev/dsp" */
|
||
|
static int S_num_channels = 6; /* number of channels to mix */
|
||
|
static int S_playback_freq = 0; /* playback frequency (in Hz) */
|
||
|
/*==========================================================================*/
|
||
|
/* non-public functions, used only within this file*/
|
||
|
|
||
|
int Snd_init_dev(void);
|
||
|
int Snd_restore_dev(void);
|
||
|
|
||
|
void Chan_reset(Channel *chan); /* init channel structure */
|
||
|
|
||
|
/* start a sample playing on a channel */
|
||
|
void Chan_assign(Channel *chan, const Sample *snd);
|
||
|
|
||
|
/* mix all channels together into the 'mix' structure */
|
||
|
int Chan_mixAll(Mix *mix, Channel *ch);
|
||
|
|
||
|
/* used by Chan_mixAll to mix the 1st channel */
|
||
|
int Chan_copyIn(Channel *chan, Mix *mix);
|
||
|
|
||
|
/* used by Chan_mixAll to mix a loop in the 1st channel */
|
||
|
int Chan_copyIn_loop(Channel *chan, Mix *mix);
|
||
|
|
||
|
/* used by Chan_mixAll to mix the middle channels */
|
||
|
int Chan_mixIn(Channel *chan, Mix *mix);
|
||
|
|
||
|
/* used by Chan_mixAll to mix the last channel */
|
||
|
int Chan_finalMixIn(Channel *chan, Mix *mix);
|
||
|
|
||
|
|
||
|
/* alloc mem for mix buffer, and deallocate function */
|
||
|
/* The sound channels are mixed together into the mix buffer */
|
||
|
/* then the mix buffer data is sent directly to the sound device */
|
||
|
void Mix_alloc(Mix *mix, int size);
|
||
|
void Mix_dealloc(Mix *mix);
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
/* justing for testing, normally not called */
|
||
|
void
|
||
|
dump_snd_list(void)
|
||
|
{
|
||
|
int i=0;
|
||
|
|
||
|
for(i=0; i<S_num_sounds; i++) {
|
||
|
printf("snd %d: len = %d \n", i, S_sounds[i].len );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Snd_init(int num_snd, const Sample *sa, int frequency,
|
||
|
int channels, const char *dev)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
S_num_sounds = num_snd;
|
||
|
S_sounds = sa; /* array of sound samples*/
|
||
|
S_playback_freq = frequency;
|
||
|
S_num_channels = channels;
|
||
|
S_snddev= dev; /* sound device, eg /dev/dsp*/
|
||
|
|
||
|
if (S_sounds==NULL)
|
||
|
return EXIT_FAILURE;
|
||
|
|
||
|
result=Snd_init_dev();
|
||
|
|
||
|
if (result==EXIT_SUCCESS) {
|
||
|
S_mixerStatus=1;
|
||
|
}
|
||
|
else {
|
||
|
S_mixerStatus=0;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Snd_restore(void)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
if(!S_mixerStatus)
|
||
|
return EXIT_FAILURE;
|
||
|
|
||
|
result=Snd_restore_dev();
|
||
|
|
||
|
if (result==EXIT_SUCCESS) {
|
||
|
S_mixerStatus=0;
|
||
|
}
|
||
|
else {
|
||
|
S_mixerStatus=0;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
/* volume control not implemented yet.*/
|
||
|
int
|
||
|
Snd_effect(int sound_num, int channel)
|
||
|
{
|
||
|
if(!S_mixerStatus)
|
||
|
return EXIT_FAILURE;
|
||
|
|
||
|
/* make sure a valid sound # was passed in */
|
||
|
if(sound_num<0 || sound_num>=S_num_sounds)
|
||
|
return EXIT_FAILURE;
|
||
|
|
||
|
/* make sure a valid channel # was passed in */
|
||
|
if(channel<0 || channel>=S_num_channels)
|
||
|
return EXIT_FAILURE;
|
||
|
|
||
|
if(S_sounds[sound_num].data != NULL) {
|
||
|
write(S_fd_pipe[1], &sound_num, sizeof(sound_num));
|
||
|
write(S_fd_pipe[1], &channel, sizeof(channel));
|
||
|
}
|
||
|
else {
|
||
|
fprintf(stderr,"Referencing NULL sound entry\n");
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/*============================================================================*/
|
||
|
int
|
||
|
Snd_init_dev(void)
|
||
|
{
|
||
|
int whoami;
|
||
|
S_fd_snddev = -1;
|
||
|
|
||
|
S_son_pid = 0;
|
||
|
|
||
|
if(access(S_snddev,W_OK) != 0) {
|
||
|
perror("no access to sound device");
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
S_fd_snddev = open(S_snddev,O_WRONLY);
|
||
|
|
||
|
if(S_fd_snddev < 0) {
|
||
|
perror("cannot open sound device");
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
close(S_fd_snddev);
|
||
|
|
||
|
if(pipe(S_fd_pipe) < 0) {
|
||
|
perror("cannot create pipe for sound control");
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
/* now setup 2nd process for writing the data... */
|
||
|
if((whoami = fork()) < 0) {
|
||
|
perror("cannot fork sound driver\n");
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
if(whoami != 0) { /* successfully created son */
|
||
|
close(S_fd_pipe[0]); /* close end for reading */
|
||
|
S_son_pid = whoami;
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/* Here is the code for the son... */
|
||
|
{
|
||
|
int sound_num,ch,i;
|
||
|
struct timeval tval = {0L,0L};
|
||
|
fd_set readfds,dsp;
|
||
|
Mix mix;
|
||
|
int fragsize;
|
||
|
Channel *chan;
|
||
|
|
||
|
chan = (Channel *)malloc(sizeof(Channel) * S_num_channels);
|
||
|
|
||
|
for(i=0; i<S_num_channels; i++)
|
||
|
Chan_reset( chan+i );
|
||
|
|
||
|
S_fd_snddev = open(S_snddev,O_WRONLY);
|
||
|
if(S_fd_snddev < 0) {
|
||
|
perror("Cannot open sound device");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
#if defined(HAVE_LINUX_SOUND)
|
||
|
{
|
||
|
int frag;
|
||
|
frag = FRAG_SPEC; /*defined in soundIt.h */
|
||
|
|
||
|
ioctl(S_fd_snddev, SNDCTL_DSP_SETFRAGMENT, &frag);
|
||
|
|
||
|
if(ioctl(S_fd_snddev,SNDCTL_DSP_SPEED, &S_playback_freq)==-1)
|
||
|
perror("Sound driver ioctl");
|
||
|
|
||
|
fragsize=0;
|
||
|
if(ioctl(S_fd_snddev,SNDCTL_DSP_GETBLKSIZE, &fragsize)==-1)
|
||
|
perror("Sound driver ioctl");
|
||
|
}
|
||
|
#elif defined(HAVE_SUN_SOUND)
|
||
|
{
|
||
|
audio_info_t ainfo;
|
||
|
|
||
|
AUDIO_INITINFO(&ainfo);
|
||
|
ainfo.play.precision = 16;
|
||
|
ainfo.play.sample_rate = S_playback_freq;
|
||
|
ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
|
||
|
ainfo.play.channels = 1;
|
||
|
ainfo.play.port = AUDIO_LINE_OUT|AUDIO_HEADPHONE|AUDIO_SPEAKER;
|
||
|
if(ioctl(S_fd_snddev,AUDIO_SETINFO, &ainfo)==-1)
|
||
|
perror("Sound driver ioctl");
|
||
|
|
||
|
fragsize=512;
|
||
|
}
|
||
|
#elif defined(HAVE_HP_SOUND)
|
||
|
{
|
||
|
struct audio_describe adescribe;
|
||
|
struct audio_gain again;
|
||
|
struct audio_limits alimits;
|
||
|
int i;
|
||
|
int best_rate;
|
||
|
int temp;
|
||
|
|
||
|
if(ioctl(S_fd_snddev, AUDIO_DESCRIBE, &adescribe)==-1)
|
||
|
perror("Sound driver ioctl: Audio Describe");
|
||
|
|
||
|
/*
|
||
|
printf("Audio Device: ");
|
||
|
switch(adescribe.audio_id) {
|
||
|
case AUDIO_ID_PSB2160:
|
||
|
printf("PSB 2160\n");
|
||
|
break;
|
||
|
case AUDIO_ID_CS4215:
|
||
|
printf("CS 4215\n");
|
||
|
break;
|
||
|
default:
|
||
|
printf("Unknown\n");
|
||
|
break;
|
||
|
}
|
||
|
printf("Samplerates:");
|
||
|
for(i=0; i<adescribe.nrates; i++)
|
||
|
printf(" %d", adescribe.sample_rate[i]);
|
||
|
printf("\nMax bits per sample: %d\n", adescribe.max_bits_per_sample);
|
||
|
printf("Channels: %d\n", adescribe.nchannels);
|
||
|
*/
|
||
|
|
||
|
if(adescribe.max_bits_per_sample < 16)
|
||
|
printf("Not enough bits\n");
|
||
|
|
||
|
temp = AUDIO_FORMAT_LINEAR16BIT;
|
||
|
if(ioctl(S_fd_snddev, AUDIO_SET_DATA_FORMAT, temp)==-1)
|
||
|
perror("Sound driver ioctl: Audio Set Data Format");
|
||
|
|
||
|
best_rate = 0;
|
||
|
for(i=0; i<adescribe.nrates; i++)
|
||
|
if(abs(adescribe.sample_rate[i]-S_playback_freq)
|
||
|
< abs(best_rate-S_playback_freq))
|
||
|
best_rate = adescribe.sample_rate[i];
|
||
|
if(abs(best_rate-S_playback_freq) > 1050)
|
||
|
printf("No good sample rate\n");
|
||
|
if(ioctl(S_fd_snddev, AUDIO_SET_SAMPLE_RATE, best_rate)==-1)
|
||
|
perror("Sound driver ioctl: Audio Set Sample Rate");
|
||
|
|
||
|
/* AUDIO_OUT_LINE | AUDIO_OUT_INTERNAL | AUDIO_OUT_EXTERNAL */
|
||
|
if(ioctl(S_fd_snddev, AUDIO_SET_OUTPUT, AUDIO_OUT_EXTERNAL)==-1)
|
||
|
perror("Sound driver ioctl: Audio Set Output");
|
||
|
|
||
|
again.cgain[0].transmit_gain = AUDIO_MAX_GAIN;
|
||
|
again.cgain[0].monitor_gain = AUDIO_OFF_GAIN;
|
||
|
again.cgain[1].transmit_gain = AUDIO_MAX_GAIN;
|
||
|
again.cgain[1].monitor_gain = AUDIO_OFF_GAIN;
|
||
|
again.channel_mask = AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT;
|
||
|
if(ioctl(S_fd_snddev, AUDIO_SET_GAINS, &again)==-1)
|
||
|
perror("Sound driver ioctl: Audio Set Gain");
|
||
|
|
||
|
/*
|
||
|
alimits.max_transmit_buffer_size = 512;
|
||
|
alimits.max_receive_buffer_size = 512;
|
||
|
if(ioctl(S_fd_snddev, AUDIO_SET_LIMITS, &alimits)==-1)
|
||
|
perror("Sound driver ioctl: Audio Set Limits");
|
||
|
|
||
|
if(ioctl(S_fd_snddev, AUDIO_GET_LIMITS, &alimits)==-1)
|
||
|
perror("Sound driver ioctl: Audio Get Limits");
|
||
|
|
||
|
fragsize=alimits.max_transmit_buffer_size;
|
||
|
*/
|
||
|
fragsize = 1024;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*printf("after: block size: %d \n", fragsize);*/
|
||
|
|
||
|
/* init mixer object*/
|
||
|
Mix_alloc(&mix, fragsize);
|
||
|
|
||
|
close(S_fd_pipe[1]); /* close end for writing */
|
||
|
|
||
|
FD_ZERO(&dsp);
|
||
|
FD_SET(S_fd_snddev, &dsp);
|
||
|
|
||
|
FD_ZERO(&readfds);
|
||
|
FD_SET(S_fd_pipe[0], &readfds);
|
||
|
|
||
|
/* printf("soundIt library v"SOUNDIT_VERS" initialized.\n");*/
|
||
|
|
||
|
for(;;) {
|
||
|
FD_SET(S_fd_pipe[0], &readfds);
|
||
|
tval.tv_sec=0L;
|
||
|
tval.tv_usec=0L;
|
||
|
select(S_fd_pipe[0]+1, &readfds,NULL,NULL,&tval);
|
||
|
|
||
|
if(FD_ISSET(S_fd_pipe[0], &readfds)) {
|
||
|
if(read(S_fd_pipe[0], &sound_num, sizeof(int))==0)
|
||
|
break;
|
||
|
|
||
|
read(S_fd_pipe[0], &ch, sizeof(int));
|
||
|
|
||
|
/*printf("chan=%d snd=%d len=%d\n",
|
||
|
ch, sound_num, S_sounds[sound_num].len);*/
|
||
|
Chan_assign(&(chan[ch]), &(S_sounds[sound_num]));
|
||
|
}
|
||
|
|
||
|
Chan_mixAll(&mix,chan);
|
||
|
|
||
|
#if defined(HAVE_LINUX_SOUND)
|
||
|
write(S_fd_snddev, mix.Vclippedbuf, fragsize);
|
||
|
#elif defined(HAVE_SUN_SOUND)
|
||
|
{
|
||
|
int stat;
|
||
|
audio_info_t ainfo;
|
||
|
static unsigned int samplecount=0;
|
||
|
|
||
|
do {
|
||
|
stat = ioctl(S_fd_snddev, AUDIO_GETINFO, &ainfo);
|
||
|
if(samplecount-ainfo.play.samples<fragsize)
|
||
|
stat = 1;
|
||
|
} while(!stat);
|
||
|
write(S_fd_snddev, (char *)mix.Vclippedbuf, sizeof(short)*fragsize);
|
||
|
samplecount+=fragsize;
|
||
|
}
|
||
|
#elif defined(HAVE_HP_SOUND)
|
||
|
{
|
||
|
struct audio_status astatus;
|
||
|
int stat;
|
||
|
|
||
|
do {
|
||
|
stat = ioctl(S_fd_snddev, AUDIO_GET_STATUS, &astatus);
|
||
|
if(astatus.transmit_exact_count<2*fragsize)
|
||
|
stat = 1;
|
||
|
} while(!stat);
|
||
|
|
||
|
write(S_fd_snddev, (char *)mix.Vclippedbuf, sizeof(short)*fragsize);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
Mix_dealloc( &mix );
|
||
|
/* printf("soundIt process exiting.\n");*/
|
||
|
close(S_fd_pipe[0]);
|
||
|
close(S_fd_pipe[1]);
|
||
|
exit (0);
|
||
|
} /* end of child process */
|
||
|
}
|
||
|
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Snd_restore_dev(void)
|
||
|
{
|
||
|
close(S_fd_pipe[0]);
|
||
|
close(S_fd_pipe[1]);
|
||
|
|
||
|
/* wait for child process to die*/
|
||
|
wait(NULL);
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
/* CHANNEL MIXING FUNCTIONS */
|
||
|
/*==========================================================================*/
|
||
|
void
|
||
|
Chan_reset(Channel *chan)
|
||
|
{
|
||
|
chan->Vstart=NULL;
|
||
|
chan->Vcurrent=NULL;
|
||
|
chan->Vlen=0;
|
||
|
chan->Vleft=0;
|
||
|
chan->Vloop=0;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
void
|
||
|
Chan_assign(Channel *chan, const Sample *snd)
|
||
|
{
|
||
|
chan->Vstart = snd->data;
|
||
|
chan->Vcurrent= chan->Vstart;
|
||
|
chan->Vlen = snd->len;
|
||
|
chan->Vleft = snd->len;
|
||
|
chan->Vloop = snd->loop;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Chan_copyIn(Channel *chan, Mix *mix)
|
||
|
{
|
||
|
int i, *p = mix->Vunclipbuf, result, min;
|
||
|
|
||
|
result = (chan->Vleft>0) ? 1 : 0;
|
||
|
min = (chan->Vleft < mix->Vsize) ? chan->Vleft : mix->Vsize;
|
||
|
|
||
|
for(i=0; i<min; i++) {
|
||
|
*p++ = (int)*chan->Vcurrent++;
|
||
|
}
|
||
|
chan->Vleft -= i;
|
||
|
|
||
|
/* fill the remaining (if any) part of the mix buffer with silence */
|
||
|
while(i<mix->Vsize) {
|
||
|
*p++ = 128;
|
||
|
i++;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Chan_copyIn_loop(Channel *chan, Mix *mix)
|
||
|
{
|
||
|
int i=0;
|
||
|
int *p = mix->Vunclipbuf;
|
||
|
int left_mix_vsize=mix->Vsize;
|
||
|
|
||
|
if (chan->Vleft==0)
|
||
|
chan->Vleft=chan->Vlen;
|
||
|
|
||
|
if(left_mix_vsize > chan->Vleft) {
|
||
|
|
||
|
/* fill the rest of the sample first */
|
||
|
for(i=0; i<chan->Vleft; i++)
|
||
|
*p++ = (int)*chan->Vcurrent++;
|
||
|
|
||
|
left_mix_vsize -= chan->Vleft;
|
||
|
chan->Vleft = chan->Vlen;
|
||
|
|
||
|
/* loop the sample by writing it repeatedly */
|
||
|
while(left_mix_vsize > chan->Vlen) {
|
||
|
chan->Vcurrent=chan->Vstart;
|
||
|
for(i=0; i<chan->Vleft; i++)
|
||
|
*p++ = (int) *chan->Vcurrent++;
|
||
|
|
||
|
left_mix_vsize-=chan->Vlen;
|
||
|
}
|
||
|
|
||
|
/* Return to the start of the Sample */
|
||
|
chan->Vcurrent=chan->Vstart;
|
||
|
|
||
|
/* If there is some space left, then fill it up :-) */
|
||
|
for(i=0;i<left_mix_vsize;i++)
|
||
|
*p++=(int)*chan->Vcurrent++;
|
||
|
|
||
|
chan->Vleft=chan->Vlen - left_mix_vsize;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
/* fill in all that fits, no looping to be done ! */
|
||
|
for(i=0; i<mix->Vsize; i++)
|
||
|
*p++ = (int) *chan->Vcurrent++;
|
||
|
|
||
|
chan->Vleft -= i;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Chan_mixIn(Channel *chan, Mix *mix)
|
||
|
{
|
||
|
int i,*p = mix->Vunclipbuf, result, min;
|
||
|
|
||
|
result = (chan->Vleft>0) ? 1 : 0;
|
||
|
min = (chan->Vleft < mix->Vsize) ? chan->Vleft : mix->Vsize;
|
||
|
|
||
|
for(i=0; i<min; i++)
|
||
|
*p++ += (int)(*chan->Vcurrent++) - 128;
|
||
|
|
||
|
chan->Vleft -= i;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*========================================================================*/
|
||
|
/* clip an int to a value between 0 and 255 */
|
||
|
#ifdef HAVE_16BIT_SOUND
|
||
|
/*
|
||
|
static inline short
|
||
|
clip(int i)
|
||
|
{
|
||
|
return ((i<0) ? 0 : ( (i>255) ? 255 : i )) * 257 - 32768;
|
||
|
}
|
||
|
*/
|
||
|
#define clip(i) ((short)((((i)<0) ? 0 : ( ((i)>255) ? 255 : (i) )) * 257 - 128*257))
|
||
|
#else
|
||
|
static inline unsigned char
|
||
|
clip(int i)
|
||
|
{
|
||
|
return (i<0) ? 0 : ( (i>255) ? 255 : i );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
int
|
||
|
Chan_finalMixIn(Channel *chan, Mix *mix)
|
||
|
{
|
||
|
int i;
|
||
|
int *p = mix->Vunclipbuf, result, min;
|
||
|
#ifdef HAVE_16BIT_SOUND
|
||
|
short *final = mix->Vclippedbuf;
|
||
|
#else
|
||
|
unsigned char *final = mix->Vclippedbuf;
|
||
|
#endif
|
||
|
|
||
|
result = (chan->Vleft>0) ? 1 : 0;
|
||
|
min = (chan->Vleft < mix->Vsize) ? chan->Vleft : mix->Vsize;
|
||
|
|
||
|
for(i=0; i<min; i++) {
|
||
|
*p += (int)(*chan->Vcurrent++) - 128;
|
||
|
*final++ = clip(*p);
|
||
|
p++;
|
||
|
}
|
||
|
chan->Vleft -= i;
|
||
|
|
||
|
/* copy rest of Vunclipbuf over to Vclippedbuf */
|
||
|
while (i<mix->Vsize) {
|
||
|
*final++ = clip(*p);
|
||
|
p++;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
void
|
||
|
Mix_alloc(Mix *mix, int size)
|
||
|
{
|
||
|
#ifdef HAVE_16BIT_SOUND
|
||
|
mix->Vclippedbuf = (short *)calloc( sizeof(short), size);
|
||
|
#else
|
||
|
mix->Vclippedbuf = (unsigned char *)calloc( sizeof(char), size);
|
||
|
#endif
|
||
|
mix->Vunclipbuf = (int *)calloc( sizeof(int), size);
|
||
|
mix->Vsize = size;
|
||
|
|
||
|
if((mix->Vclippedbuf==NULL) || (mix->Vunclipbuf==NULL)) {
|
||
|
printf("Unable to allocate memory for mixer buffer.\n");
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
void
|
||
|
Mix_dealloc(Mix *mix)
|
||
|
{
|
||
|
if(mix->Vclippedbuf)
|
||
|
free(mix->Vclippedbuf);
|
||
|
if(mix->Vunclipbuf)
|
||
|
free(mix->Vunclipbuf);
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
/* Mixes together the channels into one sound.
|
||
|
Returns # of channels currently playing *any* sound
|
||
|
Therefore, return 0 means to channels have a sample, therefore no
|
||
|
sound is playing
|
||
|
*/
|
||
|
int
|
||
|
Chan_mixAll(Mix *mix, Channel *chan)
|
||
|
{
|
||
|
int result=0, i=0;
|
||
|
|
||
|
/* Loop in the first channel ? */
|
||
|
if (chan->Vloop==0)
|
||
|
result = Chan_copyIn(chan, mix);
|
||
|
else
|
||
|
result = Chan_copyIn_loop(chan, mix);
|
||
|
|
||
|
/* we want to loop for S_num_channels-2 */
|
||
|
for(i=2; i<S_num_channels; i++)
|
||
|
result += Chan_mixIn(++chan, mix);
|
||
|
|
||
|
result += Chan_finalMixIn(++chan, mix);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*==========================================================================*/
|
||
|
/* given the name of a .raw sound file, load it into the Sample struct */
|
||
|
/* pointed to by 'sample' */
|
||
|
/* Returns -1 couldn't open/read file */
|
||
|
/* -2 couldn't alloc memory) */
|
||
|
int
|
||
|
Snd_loadRawSample(const char *file, Sample *sample, int loop)
|
||
|
{
|
||
|
FILE *fp;
|
||
|
|
||
|
sample->data = NULL;
|
||
|
sample->len = 0;
|
||
|
sample->loop = loop;
|
||
|
|
||
|
fp = fopen(file,"r");
|
||
|
|
||
|
if(fp==NULL)
|
||
|
return -1;
|
||
|
|
||
|
/* get length of the file */
|
||
|
sample->len = lseek(fileno(fp), 0, SEEK_END);
|
||
|
|
||
|
/* go back to beginning of file */
|
||
|
lseek(fileno(fp), 0, SEEK_SET);
|
||
|
|
||
|
/* alloc memory for sample */
|
||
|
sample->data = (unsigned char *)malloc(sample->len);
|
||
|
|
||
|
if(sample->data==NULL) {
|
||
|
fclose(fp);
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
fread(sample->data, 1, sample->len, fp);
|
||
|
|
||
|
fclose(fp);
|
||
|
|
||
|
return 0;
|
||
|
}
|