/* mixbas.c -- very basic realtime mix listener */ /* usage: mixbas mixfile [optional: outfile.wav] mixfile format (for each line): infilename.wav starttime amplitude [optional: rigth amplitude] if the infile is MONO then amplitude is for left channel and an extra amplitude for right channel is required. */ /* This program is for free and fun. I give it away under the GPL license, with all disclamiers and whatever. If you by any chance happends to come across any of my music, please listen to it and tell me what you think. Reine Jönsson reine@mbox314.swipnet.se */ #include #include #include #include #include #include #include #include #define MAXSOUNDS 1000 #define BLOCKSIZE 16384 #define BLOCKSAMPLES 8192 #define SAMPLERATE 44100 #define NOT_USED 0 #define NOT_STARTED 1 #define RUNNING 2 #define COMPLETED 3 #define MONO 1 #define STEREO 2 typedef struct { int active; int fh; long channels; float starttime; long startframe; int startblock,startpos; float amp,right; short *vec; char name[256]; } MIXHEADER; typedef struct { unsigned long main_id; // 'RIFF' unsigned long length; // File-lenght unsigned long wave_id; // 'WAVE' unsigned long fmt_id; // 'fmt' unsigned long fmt_length; // length of fmt_chunk, 16 bits? unsigned short format; // 1 for PCM code unsigned short channels; // 1=MONO, 2=STEREO unsigned long samplerate; unsigned long byte_per_second; unsigned short samplesize; // 1 or 2 bytes unsigned short bit; // ?? 8,12,16 bit unsigned long data_id; // 'data' unsigned long data_length; // sample count } WAV_HEADER; short* AllocateShort(long antal); //Allocates with calloc - zeroes data // Dsp out functions int InitDspOut(void); //returns filehandle to use with write(); void FreeDspOut(int fh); //sends silence closes filehandle void Show_audio_buff_info(int fh); // wavfile out functions int InitWavOut(char *name); //returns filehandle void FreeWavOut(int sh, char *name); void CreateWavHeader(WAV_HEADER *wh, long samplerate,short channels,long fileSamples); void AdjustWavHeader(char *name,long sr,short channels); long GetFileSize(char *name); //Returns file size in bytes //used only by AdjustWavHeader // Mixer functions int InitMix(MIXHEADER *m,char *name); //returns nr of sounds to play void FreeMix(MIXHEADER *m); void ShowMixHeader(MIXHEADER *m); void PlayMix(MIXHEADER *m,int sh); //used by PlayMix inline void AddStereo(short *data,short *vec,int antal,float amp); inline void AddMono(short *data,short *vec,int antal,float left,float right); int AddStereoBlock(MIXHEADER *m,short *data); int AddMonoBlock(MIXHEADER *m,short *data); short* AllocateShort(long antal) { short *vec=(short *)calloc(antal,sizeof(short)); if (!vec) { fprintf(stderr,"Could not allocate short memory.\n"); exit(1); } return(vec); } // DspOut functions int InitDspOut(void) { long blocksize,svar; long channelMode=1; //stereo=1 mono=0 long dsp_speed=SAMPLERATE; long soundFormat=AFMT_S16_LE; int sound=open("/dev/dsp",O_WRONLY); if (sound==-1) { fprintf(stderr,"Could not open /dev/dsp\n"); } svar=(2<<16)|(14); svar=ioctl(sound,SNDCTL_DSP_SETFRAGMENT,&svar); if (svar<0) printf("Error in SNDCTL_DSP_SETFRAGMENT.\n"); svar=ioctl(sound,SNDCTL_DSP_SETFMT,&soundFormat); if (svar<0) printf("Error in .\n"); svar=ioctl(sound,SNDCTL_DSP_STEREO,&channelMode); if (svar<0) printf("Error in DSP_STEREO.\n"); svar=ioctl(sound,SNDCTL_DSP_SPEED,&dsp_speed); if (svar<0) printf("Error in DSP_SPEED.\n"); // else printf("Sample rate %d.\n",dsp_speed); svar=ioctl(sound,SNDCTL_DSP_GETBLKSIZE,&blocksize); if (svar<0) printf("Error in DSP_GETBLKSIZE.\n"); if (blocksize!=BLOCKSIZE) { printf("Warning! BLOCKSIZE=%d but blocksize=%d.\n",BLOCKSIZE,blocksize); } // Show_audio_buff_info(sound); return(sound); } void FreeDspOut(int fh) { short *silence=AllocateShort(BLOCKSAMPLES); write(fh,silence,BLOCKSIZE); free(silence); close(fh); } void Show_audio_buff_info(int fh) { audio_buf_info info; ioctl(fh, SNDCTL_DSP_GETOSPACE, &info); printf("%d %d %d %d\n",info.fragments,info.fragstotal, info.fragsize,info.bytes); } // End of DspOut functions // Mix functions inline void AddStereo(short *data,short *vec,int antal,float amp) { int i; for (i=0;ifh,m->vec,BLOCKSIZE); AddStereo(data,m->vec,antalBytes/2,m->amp); if (antalBytes!=BLOCKSIZE) { m->active=COMPLETED; return(-1); } else return(0); } int AddMonoBlock(MIXHEADER *m,short *data) { int antalBytes=read(m->fh,m->vec,BLOCKSIZE>>1); AddMono(data,m->vec,antalBytes,m->amp,m->right); if (antalBytes!=(BLOCKSIZE>>1)) { m->active=COMPLETED; return(-1); } else return(0); } void StartAddStereo(MIXHEADER *m,short *data) { int antal=(BLOCKSAMPLES-m->startpos)*sizeof(short); int svar=read(m->fh,m->vec,antal); if (antal!=svar) { fprintf(stderr,"Error in StartAddStereo. Svar=%d.\n",svar); } AddStereo(&data[m->startpos],m->vec,antal>>1,m->amp); } void StartAddMono(MIXHEADER *m,short *data) { int antal=((BLOCKSAMPLES>>1)-(m->startpos>>1))*sizeof(short); int svar=read(m->fh,m->vec,antal); if (antal!=svar) { fprintf(stderr,"Error in StartAddMono. Svar=%d.\n",svar); } AddMono(&data[m->startpos],m->vec,antal,m->amp,m->right); } void PlayMix(MIXHEADER *m,int sh) { long antalBytes,antalSamples; long i; long antal,activeCnt=0; long blockCnt=0; short *data=AllocateShort(BLOCKSAMPLES); short *vec=AllocateShort(BLOCKSAMPLES); for (i=0;iname,m->active); printf("channels %d.\n",m->channels); printf("starttime %f. startframe %d.\n",m->starttime,m->startframe); printf("amp %f. rigth %f.\n",m->amp,m->right); } int InitMix(MIXHEADER *m,char *name) { FILE *fp=fopen(name,"r"); int cnt=0; int svar; char text[256],*str; WAV_HEADER wh; for (cnt=0;cntNOT_USED) { close(m[i].fh); } } } // End of Mix functions // WavOut functions long GetFileSize(char *name) { int fh=open(name,O_RDONLY); long filesize; if (fh==-1) { fprintf(stderr,"GetFileSize could not open file: %s\n",name); return(0); } filesize=lseek(fh,0,SEEK_END); close(fh); return(filesize); } void AdjustWavHeader(char *name,long sr,short channels) { long svar; long fileSize=GetFileSize(name); long fileSamples=(fileSize-sizeof(WAV_HEADER))/2; WAV_HEADER wh; FILE *fp=fopen(name,"r+b"); if (!fp) { printf("AdjustWavHeader could not open file %s.\n",name); exit(1); } CreateWavHeader(&wh,sr,channels,fileSamples); svar=fwrite(&wh,sizeof(WAV_HEADER),1,fp); if (svar!=1) { fprintf(stderr,"Could not fwrite header data.\n"); exit(1); } fclose(fp); } void CreateWavHeader(WAV_HEADER *wh, long samplerate,short channels,long fileSamples) { wh->main_id=1179011410; wh->length=36+(fileSamples*2); //36=sizeof(WAVE_HEADER)-8 wh->wave_id=1163280727; wh->fmt_id=544501094; wh->fmt_length=16; wh->format=1; //PCM code wh->channels=channels; wh->samplerate=samplerate; wh->byte_per_second=channels*samplerate*2; //2 för short wh->samplesize=channels*2; //2 för short wh->bit=16; //short wh->data_id=1635017060; wh->data_length=fileSamples*2; //2 för short } int InitWavOut(char *name) { WAV_HEADER wh; int svar; int fh=open(name,O_WRONLY|O_CREAT); if (fh==-1) { fprintf(stderr,"Could neither open or creat %d.\n"); return(0); } CreateWavHeader(&wh,SAMPLERATE,STEREO,0); svar=write(fh,&wh,sizeof(WAV_HEADER)); if (svar==-1) { fprintf(stderr,"Could not write WAV_HEADER to output file %s.\n", name); } return(fh); } void FreeWavOut(int sh, char *name) { close(sh); AdjustWavHeader(name,SAMPLERATE,STEREO); } int main(int argc,char *argv[]) { MIXHEADER *mh=(MIXHEADER *)calloc(MAXSOUNDS,sizeof(MIXHEADER)); int sh; //sound out handle int antal; if (!mh) { fprintf(stderr,"Could not calloc mixheaders.\n"); exit(1); } if (argc<2 || argc>3) { printf("mixbas mixfile [outname.wav]\n"); printf("mixfileformat: (for each line)\n"); printf("soundname starttime amp [if mono right amp]\n"); exit(1); } antal=InitMix(mh,argv[1]); if (antal>0) { if (argc==2) sh=InitDspOut(); else if (argc==3) sh=InitWavOut(argv[2]); PlayMix(mh,sh); if (argc==2) FreeDspOut(sh); else if (argc==3) FreeWavOut(sh,argv[2]); } else { printf("No sounds to play.\n"); } FreeMix(mh); free(mh); }