/* rdgen.c * * A WAV file generator for test tones * * (C) Copyright 1997-2003,2016 Fred Gleason <fredg@paravelsystems.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <sys/soundcard.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <math.h> #include <time.h> #include <wavlib.h> #define BUFFER_SIZE 16384 #define SAMPLE_RATE 48000 #define SAMPLE_SIZE 16 #define USAGE "rdgen [-f freq][-l level][-c left|right|both][-p now|rev][-t secs][-v] <wavfile>\n" int main(int argc,char *argv[]) { int i; int hFilename; unsigned char cBuffer[BUFFER_SIZE]; float fFreq=1000; float fLevel=0; float fRatio; int dChan=0; /* 0=Both, 1=Left, 2=Right */ char sChan[10]; int dPhase=0; /* 0=Normal, 1=Reverse */ char sPhase[10]; int dTime=0; int dMatch=0; int dDebug=0; int dSampleRate=0; char sFilename[128]; /* Name of audio device */ float fGain; float fAngle; unsigned long ldCount,ldTimeline=0,ldLimit=BUFFER_SIZE; short int dSample; time_t tmTimestamp,tmTime; struct wavHeader wavHeader; unsigned dBytes=0,dTotalBytes; if(argc<2) { printf(USAGE); exit(0); } if(argc==2) { if(strcmp(argv[1],"-v")==0) { printf("wavgen v"); printf(VERNUM); printf("\n"); exit(0); } } /* Get device name */ if(sscanf(argv[argc-1],"%s",sFilename)!=1) { printf("wavgen: invalid file anem\n"); exit(1); } /* Get options */ for(i=1;i<argc-1;i++) { dMatch=0; if(strcmp(argv[i],"-v")==0) { /* Version */ printf("wavgen v"); printf(VERNUM); printf("\n"); exit(0); } if(strcmp(argv[i],"-d")==0) { /* Debug Mode */ dMatch=1; dDebug=1; } if(strcmp(argv[i],"-f")==0) { /* Frequency */ dMatch=1; if(sscanf(argv[++i],"%f",&fFreq)!=1) { printf("wavgen: invalid frequency\n"); exit(1); } } if(strcmp(argv[i],"-l")==0) { /* Level */ dMatch=1; if(sscanf(argv[++i],"%f",&fLevel)!=1) { printf("wavgen: invalid level\n"); exit(1); } fLevel=-fLevel; } if(strcmp(argv[i],"-t")==0) { /* Time */ dMatch=1; if(sscanf(argv[++i],"%d",&dTime)!=1) { printf("wavgen: invalid time interval\n"); exit(1); } } if(strcmp(argv[i],"-c")==0) { /* Channel */ dMatch=1; if(sscanf(argv[++i],"%s",sChan)!=1) { printf("wavgen: invalid time interval\n"); exit(1); } if(strcasecmp(sChan,"both")==0) { dChan=0; } else { if(strcasecmp(sChan,"left")==0) { dChan=1; } else { if(strcasecmp(sChan,"right")==0) { dChan=2; } else { printf("wavgen: invalid channel\n"); exit(1); } } } } if(strcmp(argv[i],"-p")==0) { /* Phase */ dMatch=1; if(sscanf(argv[++i],"%s",sPhase)!=1) { printf("wavgen: invalid phase setting\n"); exit(1); } if(strcasecmp(sPhase,"norm")==0) { dPhase=0; } else { if(strcasecmp(sPhase,"rev")==0) { dPhase=1; } else { printf("wavgen: invalid phase setting\n"); exit(1); } } } if(dMatch==0) { printf("wavgen: invalid option\n"); exit(1); } if(dTime==0) { printf("wavgen: missing time argument\n"); exit(1); } } /* Convert db to ratio */ fRatio=pow(10,(fLevel/20)); /* Set audio characteristics */ wavHeader.wFormatTag=WAVE_FORMAT_PCM; wavHeader.wChannels=2; wavHeader.dwSamplesPerSec=SAMPLE_RATE; wavHeader.dwAvgBytesPerSec=SAMPLE_RATE*(SAMPLE_SIZE/8)*2; wavHeader.wBlockAlign=SAMPLE_SIZE/4; wavHeader.wBitsPerSample=SAMPLE_SIZE; /* Open the wav file */ hFilename=CreateWav(sFilename,&wavHeader); if(hFilename<0) { printf("wavgen: can't open wav file\n"); exit(1); } /* Display Settings (if requested) */ if(dDebug==1) { printf("--Audio Generator Settings--\n"); printf("Frequency: %5.0f Hz\n",fFreq); printf("Level: %3.1f dB\n",fLevel); printf("Channel(s): "); switch(dChan) { case 0: printf("BOTH\n"); break; case 1: printf("LEFT\n"); break; case 2: printf("RIGHT\n"); break; } printf("Phasing: "); switch(dPhase) { case 0: printf("NORMAL\n"); break; case 1: printf("REVERSE\n"); break; } printf("Effective Sample Rate: %d samples/sec\n",dSampleRate); } /* Setup time data */ time(&tmTimestamp); tmTime=tmTimestamp; if(dTime>0) { tmTimestamp+=dTime; } else { tmTimestamp--; } /* Output audio */ dTotalBytes=wavHeader.dwAvgBytesPerSec*dTime; switch(SAMPLE_SIZE) { case 8: fGain=127*fRatio; ldTimeline=0; ldLimit=BUFFER_SIZE/2; while(dBytes<dTotalBytes) { i=0; for(ldCount=ldTimeline;ldCount<ldLimit;ldCount++) { fAngle=2*PI*ldCount*fFreq/SAMPLE_RATE; if(dChan==0 || dChan==1) { cBuffer[i++]=fGain*sin(fAngle)+128; } else { cBuffer[i++]=128; } if(dChan==0 || dChan==2) { if(dPhase==0) { cBuffer[i++]=fGain*sin(fAngle)+128; } else { cBuffer[i++]=-fGain*sin(fAngle)+128; } } else { cBuffer[i++]=128; } } write(hFilename,cBuffer,BUFFER_SIZE); dBytes+=BUFFER_SIZE; ldLimit+=(BUFFER_SIZE/2); ldTimeline+=(BUFFER_SIZE/2); time(&tmTime); } break; case 16: fGain=32767*fRatio; ldTimeline=0; ldLimit=BUFFER_SIZE/4; while(dBytes<dTotalBytes) { i=0; for(ldCount=ldTimeline;ldCount<ldLimit;ldCount++) { fAngle=2*PI*ldCount*fFreq/SAMPLE_RATE; dSample=fGain*sin(fAngle); if(dChan==0 || dChan==1) { cBuffer[i++]=0xFF&dSample; cBuffer[i++]=(0xFF&(dSample>>8)); } else { cBuffer[i++]=0; cBuffer[i++]=0; } if(dChan==0 || dChan==2) { if(dPhase==1) { dSample=-dSample; } cBuffer[i++]=0xFF&dSample; cBuffer[i++]=(0xFF&(dSample>>8)); } else { cBuffer[i++]=0; cBuffer[i++]=0; } } write(hFilename,cBuffer,BUFFER_SIZE); dBytes+=BUFFER_SIZE; ldLimit+=(BUFFER_SIZE/4); ldTimeline+=(BUFFER_SIZE/4); time(&tmTime); } break; } /* close files and finish */ FixWav(hFilename,dBytes/wavHeader.wBlockAlign,dBytes); close(hFilename); exit(0); }