?? soundit.c
字號:
/* SoundIt library 0.021 Copyright 1994 Brad Pitzel pitzel@cs.sfu.ca Feel free to use/distribute/modify as long as proper credits are included.*/#include "soundit.h"#include <malloc.h>#include <limits.h> /* PATH_MAX */#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 <linux/soundcard.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).*/struct Mix { unsigned char *Vclippedbuf; int *Vunclipbuf; int Vsize; };typedef struct Mix Mix;/*==========================================================================*/struct Channel { 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 */ };typedef struct Channel Channel;/*==========================================================================*//* variables prefixed with S_ are static *//* 0 if mixer isn't initialized or init failed, 1 if mixer is good */static int sampleMixerStatus = 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();int Snd_restore_dev();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 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() { 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) { sampleMixerStatus=1; } else { sampleMixerStatus=0; } return result; }/*==========================================================================*/int Snd_restore() { int result; if (!sampleMixerStatus) return EXIT_FAILURE; result=Snd_restore_dev(); if (result==EXIT_SUCCESS) { sampleMixerStatus=0; } else { sampleMixerStatus=0; } return result; }/*==========================================================================*//* volume control not implemented yet.*/int Snd_effect( int sound_num, int channel ) { if(! sampleMixerStatus ) 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)); } return EXIT_SUCCESS; }/*============================================================================*/int Snd_init_dev() { int whoami; S_fd_snddev = -1; S_son_pid = 0; if(access(S_snddev,W_OK) != 0) { return EXIT_FAILURE; } S_fd_snddev = open(S_snddev,O_WRONLY); if(S_fd_snddev < 0) { return EXIT_FAILURE; } close(S_fd_snddev); if(pipe(S_fd_pipe) < 0) { return EXIT_FAILURE; } /* now setup 2nd process for writing the data... */ if((whoami = fork()) < 0) { 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 frag, fragsize; Channel *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) { exit(1); } frag = FRAG_SPEC; /*defined in soundIt.h */ ioctl(S_fd_snddev, SNDCTL_DSP_SETFRAGMENT, &frag); ioctl(S_fd_snddev,SNDCTL_DSP_SPEED, &S_playback_freq); fragsize=0; ioctl(S_fd_snddev,SNDCTL_DSP_GETBLKSIZE, &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); for(;;) { FD_ZERO(&readfds); FD_SET(S_fd_pipe[0], &readfds); tval.tv_sec=0L; tval.tv_usec=0L; i = select(S_fd_pipe[0]+1, &readfds,NULL,NULL,&tval); if (i > 0 && FD_ISSET(S_fd_pipe[0], &readfds)) { i = read(S_fd_pipe[0], &sound_num, sizeof(int)); if (i < sizeof(int)) break; i = read(S_fd_pipe[0], &ch, sizeof(int)); if (i < sizeof(int)) break; Chan_assign( &(chan[ch]), &(S_sounds[sound_num]) ); } Chan_mixAll(&mix,chan); write(S_fd_snddev, mix.Vclippedbuf, fragsize ); } Mix_dealloc( &mix ); close(S_fd_pipe[0]); close(S_fd_pipe[1]);/* * * Important: call _exit() and not exit() ! Otherwise parent process * files will be closed. In the case of an X11 based application, the * socket to the X server will be closed!!!! * */ _exit (0); } /*end of child process */ }/*==========================================================================*/int Snd_restore_dev() { close(S_fd_pipe[0]); close(S_fd_pipe[1]); /* wait for child process to die*/ waitpid(S_son_pid, 0, 0); return EXIT_SUCCESS; }/*==========================================================================*//* CHANNEL MIXING FUNCTIONS *//*==========================================================================*/void Chan_reset( Channel *chan ) { chan->Vstart=NULL; chan->Vcurrent=NULL; chan->Vlen=0; chan->Vleft=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; } /*==========================================================================*/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_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 */static inline unsigned char clip(int i) { return (i<0) ? 0 : ( (i>255) ? 255 : i ); } /*==========================================================================*/int Chan_finalMixIn( Channel *chan, Mix *mix ) { register int i; int *p = mix->Vunclipbuf, result, min; unsigned char *final = mix->Vclippedbuf; 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++); } chan->Vleft -= i; /* copy rest of Vunclipbuf over to Vclippedbuf */ while (i<mix->Vsize) { *final++ = clip(*p++); i++; } return result; }/*==========================================================================*/void Mix_alloc(Mix *mix, int size) { mix->Vclippedbuf = (unsigned char *)calloc( sizeof(char), size); mix->Vunclipbuf = (int *)calloc( sizeof(int), size); mix->Vsize = size; if ((mix->Vclippedbuf==NULL)||(mix->Vunclipbuf==NULL)) { 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; result = Chan_copyIn( 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) */intSnd_loadRawSample( const char *file, Sample *sample ) { FILE *fp; sample->data = NULL; sample->len = 0; 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; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -