siggen-2.3.10/0002700000175000017500000000000011011657545011514 5ustar jjfamilysiggen-2.3.10/generator.c0000600000175000017500000004362711011656112013647 0ustar jjfamily/* generator.c * The main DSP signal generation functions plus some misc. functions * Jim Jackson Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* History................... * * 11May08 Bug in mksweep with x10 or x100 options and wide ranges * caused int overflow problems and corrupt waveforms * 18Jun98 altered to make it compile on systems without soundcard * or dsp support. * 18Mar97 Moved maketone() into here * 17Mar97 added a mksweep() function - but as a separate function * is not available from the generate() function * 09Feb97 made buffer mixing routine take account of gains, in order * to maintain maximum absolute sample sizes, while maintaining * relative sizes of mixed samples. * 07Feb97 discovered and fixed bug in generating sin/cos waves * which are generated over very many cycles. This caused w * (the radians counter) to get >> 2*PI and meant that * the sin calculation got slightly inaccurate causing a mismatch * when the buffer is looped. Fix is to check if w > 2*PI and * if so sub 2*PI. Now the beginning and end of the buffer match * 19Jan97 Added cosine - sin with 90 degrees offset * 02Jan97 Triangle generation sorted. * 29Dec96 Added amplitude factor -A N where N is a percentage. * The sample is created to optimally fill the sample space when * N is 100 (the default value). The samples generated are scaled * by N/100, overly large values simply being 'clipped'. * To create a trapezoid wave form, generate a triangle wave * with N>100, depending on slope needed on waveform. * 18Dec96 Started splitting up stuff into different files so that I can * write some different front ends. All the code to create the * samples is in generator.c, and some misc. stuff in misc.c * --Dec96 Added noise generator using the random function - sounds ok * Need to figure what to do to get pink noise - I think! * --Oct96 Original Linux version. Fixed faulty sample generation * in DOS program - you have to generate samples over several * cycles to ensure that a you can put samples end-to-end * to fill a second, see comments in mksin(). Added stereo * and antiphase stuff. Eventually worked out how to generate * square/pulse signals accurately, and sawtooth. * Triangle still to do. */ /* A one second's worth buffer of samples is generated (samplerate samples) * for 8 bit mono this is bytes, for 16 mono this is doubled */ #include #include #include #include #include #include #include #include #include #include "config.h" #ifndef PI # ifdef M_PI # define PI M_PI # else # define PI 3.141592653589793 # endif #endif #define chkword(a,b) ((n>=a)&&(strncasecmp(p,b,n)==0)) extern int vflg; /* within this package vflg must be >=2 for diagnostics */ #define VERBOSE (vflg>1) /* mk8bit(bf,ip,N) convert N 16 bit samples from *ip to 8 bit samples * in bf */ mk8bit(bf,ip,N) unsigned char *bf; short int *ip; int N; { unsigned char *p; for (p=bf; N--; ) { *p++=(unsigned char)(((*ip++)>>8)+128); } return(0); } /* mixplaybuf(a,b,c,N,afmt) mix N samples from buffers b and c into * sound play buffer a * afmt defines format of samples */ mixplaybuf(a,b,c,N,afmt) unsigned char *a,*b,*c; int N,afmt; { int i,word; word=(afmt==AFMT_S16_LE); for (i=0; i>1; if (afmt==AFMT_S16_LE) { /* 16 bit mixing...... */ p=(short int *)b; q=(short int *)c; r=(short int *)a; for (i=0; i32767 ) { dF=(dF+1)/2; D=(D+1)/2; } if (VERBOSE) { printf("Generating sweep waveform from %d Hz to %d Hz\n",Fmin,Fmax); printf("Centre Freq. %d Hz, sweep scaling %d/%d\n",F,dF,D); } fmb=(short int *)FMbuf; if (afmt==AFMT_S16_LE) { wb=(short int *)wavbuf; for (x=i=0,vp=(short int *)bf; i>2*PI * becomes inaccurate, so in the increment loop we check if w>2*PI * and if so subtract 2*PI so that the value is kept low for each cycle */ n=N/(h=hcf(N,freq)); /* n = N/hcf(N,freq) is number of samples to create */ nc=freq/h; /* nc is number of wavelengths generated */ if (VERBOSE) { printf("%dHz at a sampling rate/sec of %d, scaled by %d/100\n", freq,N,A); printf("%d samples for %d cycle(s).\n",n,nc); } pi2=PI+PI; w=((float)(R)*PI)/180.0; wi=((float)nc*2*PI)/(float)n; if (afmt==AFMT_U8) { sc=(float)A*127.0/100.0; for (i=0,p=bf; ipi2)?pi2:0)) ) { t=128+rint(sc*sin(w)); *p++=(t>255)?255:((t<0)?0:t); } } else if (afmt==AFMT_S16_LE) { sc=(float)A*32767.0/100.0; for (i=0,vp=(short int *)bf; ipi2)?pi2:0)) ) { t=rint(sc*sin(w)); *vp++=(t>32767)?32767:((t<-32767)?-32767:t); } } else return(0); return(n); } /* mksquare(bf,bfn,freq,A,N,R,afmt) * square wave - calls mkpulse with 50% mark/space ratio, scaled by A/100 */ mksquare(bf,bfn,freq,A,N,R,afmt) char *bf; int bfn; unsigned freq,A,N; int R,afmt; { return(mkpulse(bf,bfn,freq,A,N,50,afmt)); } /* mkpulse(bf,bfn,freq,A,N,R,afmt) * rectangular wave of freq Hertz played at N samples/sec, * mark/space ratio R (%) * scaled by A/100, 50% is equal mark/space, <50% is mark127)?127:t); b=A*128/100; b=128-((b>128)?128:b); for (i=0,p=bf; i32767)?32767:t; for (i=0,vp=(short int *)bf; i127)?127:((b<-128)?-128:b))); } } else if (afmt==AFMT_S16_LE) { t=2*A*32767/100; for (i=0,vp=(short int *)bf; i32767)?32767:((b<-32767)?-32767:b)); } } else return(0); return(n); } /* mktriangle(bf,bfn,freq,A,N,R,afmt) * triangle wave of freq Hertz, played at N samples/sec, scaled by A/100 */ mktriangle(bf,bfn,freq,A,N,R,afmt) char *bf; int bfn; unsigned int freq,A,N; int R,afmt; { int i,n,nc,t,d,b,h; short int *vp; unsigned char *p; n=N/(h=hcf(N,freq)); /* n = N/hcf(N,freq) is number of samples to create */ nc=freq/h; /* nc is number of wavelengths generated */ if (VERBOSE) { printf("%dHz at a sampling rate/sec of %d, scaled by %d/100\n", freq,N,A); printf("%d samples for %d cycle(s).\n",n,nc); } /* for sawtooth we use b=(i*nc)%n to give a value upto n-1 */ /* if the value is < n/2 ok for upramp else set to n-b to down ramp */ /* then adjust by subtracting n/2 to give a range of -n/2 to +n/2 */ /* we then scale to be in the correct range and clip if necessary */ d=n/2; if (afmt==AFMT_U8) { t=2*A*127/100; for (i=0,p=bf; i127)?127:((b<-128)?-128:b))); } } else if (afmt==AFMT_S16_LE) { t=2*A*32767/100; for (i=0,vp=(short int *)bf; i32767)?32767:((b<-32767)?-32767:b)); } } else return(0); return(n); } /* mknoise(bf,bfn,freq,A,N,R,afmt) * make noise - freq is ignored. samples scaled by A/100 * All bf is filled with pseudo random values */ mknoise(bf,bfn,freq,A,N,R,afmt) char *bf; int bfn; unsigned freq,A,N; int R,afmt; { unsigned int i,n,r; unsigned char c,*p; short int *vp; short int v; int t,b; n=bfn; /* number of samples to generate - fill bf */ if (afmt==AFMT_S16_LE) n/=2; /* if 16 bit samples = buffsize/2 */ if (VERBOSE) { printf("Noise, %d samples/sec\n%d samples.\n",N,n); } srand(time(NULL)); if (afmt==AFMT_U8) { for (i=0,p=bf; i>8)&255); } } else if (afmt==AFMT_S16_LE) { t=A*32767/100; t=(t>32767)?32767:t; for (i=0,vp=(short int *)bf; i>8)&0xFF)+(rand()&0xFF00)); } } else return(0); return(n); } /* mknull(bf,bfn,freq,A,N,R,afmt) * make quiet - fill the buffer with zero values */ mknull(bf,bfn,freq,A,N,R,afmt) char *bf; int bfn; unsigned freq,A,N; int R,afmt; { unsigned int i,n,r; unsigned char c,*p; short int *vp; short int v; int t,b; n=bfn; /* number of samples to generate - fill bf */ if (afmt==AFMT_S16_LE) n/=2; /* if 16 bit samples = buffsize/2 */ if (VERBOSE) { printf("Quiet, %d samples/sec\n%d samples.\n",N,n); } if (afmt==AFMT_U8) { for (i=0,p=bf; i(N/2)) return(0); n=strlen(p=wf); for (i=0; WavNAMES[i]!=NULL; i++) { if (chkword(2,WavNAMES[i])) { if (VERBOSE) { fputs(wf,stdout); fputs(" matches generator function : ",stdout); fputs(WavNAMES[i],stdout); fputs("\n",stdout); } if (R==-1) R=WavDefr[i]; if ((n=(*(WavFuncs[i]))(buf,N,fr,A,S,R,afmt))==0) return(0); /* put any common post-processing here */ /* here we fill the full N byte buf up with h (N/n) basic samples */ nc=(afmt==AFMT_S16_LE)?(n<<1):n ; for (p=buf+nc,i=1,h=N/nc; i Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. siggen-2.3.10/mixer.c0000644000175000017500000000417507337767112013033 0ustar jjfamily/* mixer.c * Simple Linux Mixer Functions * Jim Jackson Wed Mar 15 2000 */ /* mixer.c: (version 1) Mar 2000 */ #include #include #include #include #include #include #include #include #include "mixer.h" #define EFAIL -1 #define TRUE 1 #define FALSE 0 int mixFD=-1; /* Mixer File Descriptor */ int devmask=0; /* Defines which mixer channels are present */ int recmask=0; /* Defines which devices can be an input device */ int sources=0; /* Defines which devices are the current input dev(s) */ int stereodevs=0; /* Defines which devices are stereo */ char *devname[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; /* Gives a list of names for the various mixer channels */ /* mixinit(DEV) open mixer device DEV and interrogate it setting up * various parameters. */ mixinit(DEV) char *DEV; { if (((mixFD = open(DEV, O_RDONLY)) >= 0) && (ioctl(mixFD, SOUND_MIXER_READ_DEVMASK, &devmask) >= 0) && (ioctl(mixFD, SOUND_MIXER_READ_RECMASK, &recmask) >= 0) && (ioctl(mixFD, SOUND_MIXER_READ_RECSRC, &sources) >= 0) && (ioctl(mixFD, SOUND_MIXER_READ_STEREODEVS, &stereodevs) >= 0)) { return(mixFD); } return(-1); } /* isdev(dev,n) check string dev against the list of mixer device names * and if found return device/channel device number * otherwise return -1 */ isdev(dev) char *dev; { int i,n; if (dev==NULL) return(-1); n=strlen(dev); for (i=0; i=0) sources=i; return(st); } GET_MIX_INPUT_DEV() { int i; for ( i=0; i Copyright 1997-2008 */ #include "config.h" #define VERSTR "%s Ver. %s Ncurses based Digital Signal Generator" extern int vflg,dflg,vikeys; extern char *sys; extern char dac[]; /* name of output device */ extern int resolution; /* 1 = 1Hz resolution, 10 = 0.1HZ, * 100=0.01 */ extern int DAC; extern unsigned int samplerate; /* Samples/sec */ extern unsigned int stereo; /* stereo mono */ extern unsigned int afmt; /* format for DSP */ extern int Bufspersec; /* Number of Buffers per sec */ extern int Nfragbufs; /* number of driver buffers */ extern int fragsize; /* size of driver buffer fragments */ extern int fragsamplesize; /* size of fragments in samples */ extern int LWn; /* no. of specified loadable waveforms */ extern char **LWaa; /* array of specifed loadable waveforms */ /* channel 1 - or mono..... */ extern char wf[32]; /* waveform type */ extern unsigned int freq; /* signal frequency */ extern int ratio; /* used in pulse, sweep etc */ extern int Gain; /* Amplification factor */ /* channel 2 when in stereo mode ..... */ extern char wf2[32]; /* waveform type */ extern unsigned int freq2; /* signal frequency */ extern int ratio2; /* used in pulse, sweep etc */ extern int Gain2; /* Amplification factor */ extern int phase; /* phase diff with chan1 */ siggen-2.3.10/wavfile.c0000600000175000017500000001761411011656666013331 0ustar jjfamily/* wavfile.c * WAV File handling routines for reading/writing samples from buffers etc. * Jim Jackson Aug 97 */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* These functions are simplistic single threaded functions for handling * WAV files. A single WavValues structure is used to record WAV file * parameters such as samplerate, stereo/mono, and the afmt (8/16) * * Typical uses...... * * Writing WAV files * * Open a FILE * for writing * call fWAVwrhdr() with appropriate audio parameters. Don't worry * if you don't know how many samples are to be written yet. * call fWAVwrsamples() to write samples away to file. While doing this * keep account of the number of samples you have written away. * When finished writing samples call fWAVwrhdr() again but this time * give it the correct number of samples parameter - the file will be * rewound and the correct headers (RIFF/WAV/DATA) will be written. * * e.g. f=fopen("sample.wav","W"); * if (f==NULL) { do error processing etc..... } * stereo=0; / * mono data * / * afmt=16; / * 16 bit data * / * samplerate=32000; / * samplerate * / * Ns=0; * fWAVwrhdr(f,Ns,samplerate,afmt,stereo); * while (samples_to_write) { * fWAVwrsamples(f,buf,bufsize); * Ns+=(bufsize>>(afmt==16)); / * if 16 bit divide by 2 to get * * number of samples * / * } * fWAVwrhdr(f,Ns,samplerate,afmt,stereo); * fclose(f); * * When writing RAW files then there must be a call to fWAVinit() * with the sound parameters, then use the fWAVwrsamples() function. * Of course there are no calls to fWAVwrhdr() 'cos RAW files don't have * headers! * * Reading WAV files * * Open wav file with the fWAVopen() function * Use the fWAVsamplerate(), fWAVafmt(), fWAVstereo() and fWAVsamples() * to access those parameters. * Read the number of samples in the file and use them. * close the file * * e.g. f=fWAVopen("samples.wav"); * if (f==NULL) { do error stuff...... } * N=fWAVsamples(); / * get number of samples * / * S=fWAVsamplerate(); / * get samplerate * / * stereo=fWAVstereo(); / * ditto stereo/mono status * / * afmt=fWAVafmt(); / * ditto 8/16 bit * / * for ( i=0; i #include #include #include #include #include #include #include #include #include #include "wavsubs.h" struct WavValues *W=NULL; /* fWAV* functions are single threaded * and the call to fWAVwrhdr or fWAVopen * can set this up with the audio params. */ /* fWAVdebug(f) write out state of struct WavValues *W to FILE *f */ fWAVdebug(f) FILE *f; { if (W==NULL) { fprintf(f,"struct WavValues *W is NULL\n"); return(0); } fprintf(f,"Setup struct WavValues.....\n"); fprintf(f," %d %s, %s, samples/sec\n",W->samplerate, (W->stereo)?"stereo":"mono", (W->afmt==AFMT_U8)?"unsigned 8 bit": ((W->afmt==AFMT_S16_LE)?"signed 16 bit, little endian": "Unknown audio format")); fprintf(f," %d samples, %d Bytes per sec, %d Bytes per sample\n", W->samples, W->Bps, W->Bypsam); return(0); } /* fWAVinit(Ns,samplerate,afmt,stereo) * Initialises the struct WavValues *W with values derived from * the calling parameters, so that other fWAVxxxx functions work * returns 0 if all ok, else returns -1 and errno is set. */ fWAVinit(Ns,samplerate,afmt,stereo) int Ns,samplerate,afmt,stereo; { int st; if ((W=Winit(W,Ns,samplerate,afmt,stereo))==NULL) { return(-1); } return(0); } /* fWAVopen(fn) attempt to open file with name fn for reading * read WAV header and setup *W * return FILE * of opened file * return NULL if file doesn't exist or is not a WAV file. */ FILE *fWAVopen(fn) char *fn; { FILE *f; if ((f=fopen(fn,"r"))==NULL) return(NULL); if (W==NULL && (W=NewWavValues())==NULL) { errno=ENOMEM; fclose(f); return(NULL); } errno=EINVAL; if ((isriff(f)==-1) || (errno=wavreadfmt(f,W))) { fclose(f); return(NULL); } return(f); } /* fWAVwrfile(f,bf,bfn,Ns,samplerate,afmt,stereo) * write riff and wav hdr for Ns samples of appropriate format then * Write Ns samples from buffer bf, of size bfn bytes, to file f */ fWAVwrfile(f,bf,bfn,Ns,samplerate,afmt,stereo) FILE *f; unsigned char *bf; int bfn,Ns,samplerate,afmt,stereo; { int st,n; if (fWAVwrhdr(f,Ns,samplerate,afmt,stereo)==-1) return(-1); n=Ns<<(afmt==16); /* set n to number of samples in buffer */ for (;;) { if (n<=bfn) { if (n) st=wavwrite(f,W,bf,n); break; } n-=bfn; if ((st=wavwrite(f,W,bf,bfn))==0) break; } return((st)?0:-1); } /* fWAVwrhdr(f,Ns,samplerate,afmt,stereo) * write riff and wav hdrs for Ns samples of appropriate format to file f */ fWAVwrhdr(f,Ns,samplerate,afmt,stereo) FILE *f; int Ns,samplerate,afmt,stereo; { int st; if ((W=Winit(W,Ns,samplerate,afmt,stereo))==NULL) { return(-1); } setendian(); fflush(f); rewind(f); riffhdr(f,(Ns<<(afmt==16))+36); if (st=wavwritefmt(f,W)) { errno=st; return(-1); } return(0); } /* fWAVwrsamples(f,bf,N) write bf of size N to FILE *f * return number of samples written or 0 if error */ fWAVwrsamples(f,bf,N) FILE *f; unsigned char *bf; int N; { return(wavwrite(f,W,bf,N)); } /* fWAVrdsamples(f,bf,N) read bf of size N from FILE *f * return number of samples read or 0 if error */ fWAVrdsamples(f,bf,N) FILE *f; unsigned char *bf; int N; { return(wavread(f,W,bf,N)); } /* writecyclic(fd,bf,bfn,Ns) bf is a sample buffer of size bfn bytes. * writecyclic writes Ns bytes from this buffer * to fd, treating the buffer as circular. */ writecyclic(fd,bf,bfn,Ns) int fd; unsigned char *bf; int bfn,Ns; { int i; for (;;) { if (Ns<=bfn) { return(write(fd,bf,Ns)); } Ns-=bfn; if (write(fd,bf,bfn) < 0) return(-1); } } /* * playloop(fd,bf,bfn,N) bf is a sample buffer of size bfn bytes. * play the buffer cyclically (in a loop) in chunks of N * */ playloop(fd,bf,bfn,N) int fd; unsigned char *bf; int bfn; int N; { int i; unsigned char *p; for (;;) { for ( p=bf,i=0; i<= (bfn-N); i+=N) { if (write(fd,p+i,N) < 0) return(0); /* check here if need to supend output or handle keypresses etc*/ } if ((i!=bfn) && (write(fd,p+i,bfn-i)<0)) return(0); } } /* fWAVsamplerate() return samplerate of opened file. * fWAVafmt() return afmt of opened file. * fWAVstereo() return stereo mode of opened file. * fWAVsamples() return Number of samples in opened file. * or -1 if non opened */ fWAVsamplerate() { if (W==NULL) return(-1); return(W->samplerate); } fWAVafmt() { if (W==NULL) return(-1); return(W->afmt); } fWAVstereo() { if (W==NULL) return(-1); return(W->stereo); } fWAVsamples() { if (W==NULL) return(-1); return(W->samples); } siggen-2.3.10/soundinfo.c0000600000175000017500000002133711011656566013674 0ustar jjfamily/* soundinfo.c * Describes the Linux Sound system support * Jim Jackson * * Date Vers Comment * ----- ----- --------------- * 27Oct96 1.0 Initial Program Built from generic filter.c * Reports mixer capabilities etc. * 18Nov96 1.1 Added DSP info */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /***MANPAGE***/ /* soundinfo: (version 1) 27Oct96 NAME: soundinfo - Describes the Linux Sound system support SYNOPSIS: soundinfo [-v] [options] DESCRIPTION: Describes the Linux Sound system support on the system. Mixer devices, DSP capabilities etc. FLAGS: -h give usage -v verbose output OPTIONS: NOTES: BUGS: This program is covered by the GNU General Public License, see file COPYING for further details. Any questions, suggestions or problems, etc. should be sent to Jim Jackson Email Internet: jj@franjam.org.uk */ /***INCLUDES***/ /* includes files */ #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #else #include #endif /***DEFINES***/ /* defines */ #define VERSION "2.3.10 (May 2008)" #define MIXDEV "/dev/mixer" #define DSPDEV "/dev/dsp" #define EFAIL -1 #define TRUE 1 #define FALSE 0 #define nl puts("") #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) /***GLOBALS***/ /* global variables */ char *sys; short int debug; /* set if the -d flag is used */ short int vflg; /* set if -v flag used */ /***DECLARATIONS***/ /* declare non-int functions */ char *delnl(),*reads(),*sindex(), *sindex_nc(),*tab(),*ctime(); FILE *fopen(),*mfopen(); /***MAIN***/ /* main - for program soundinfo * Describes the Linux Sound system support */ main(argc,argv) int argc; char **argv; { int i,j,n,st; char fname[132],*fnm,*p; int fd; argv[argc]=NULL; sys=*argv++; argc--; if ((p=strrchr(sys,'/'))!=NULL) { sys=p+1; } debug=vflg=FALSE; printf("%s Ver. %s (c) 1996-2008 Jim Jackson\n",sys,VERSION); while (argc && **argv=='-') /* all flags and options must come */ { n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (*p==0) n=atoi(p+1); /* e.g. num. option -n23 */ else /* check for single char. flags */ { for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='d') debug=TRUE; else if (*p=='v') vflg=TRUE; else { *fname='-'; *(fname+1)=*p; *(fname+2)=0; exit(help(err_rpt(EINVAL,fname))); } } } } if ((fd = open(fnm=MIXDEV, O_RDONLY)) < 0) { err_rpt(errno,fnm); } else { do_mix(fd,fnm); } if ((fd = open(fnm=DSPDEV, O_RDWR)) < 0) { err_rpt(errno,fnm); } else { do_dsp(fd,fnm); } exit(st); } /***HELP***/ /* help(e) print brief help message - return parameter given */ help(e) int e; { puts("\n\ Describes some features of the Linux Sound system support in the kernel.\n\ "); printf("\ Usage: %s\n\ ",sys); return(e); } do_dsp(fd,dev) int fd; char *dev; { int i,n; int caps,fmts,blksize; char buf[130],*p; audio_buf_info auobf,auibf; if (ioctl(fd, SNDCTL_DSP_GETCAPS , &caps) < 0) { return(err_rpt(errno,"Reading DSP capabilities.")); } if (ioctl(fd, SNDCTL_DSP_GETFMTS , &fmts) < 0) { return(err_rpt(errno,"Reading DSP formats.")); } if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE , &blksize) < 0) { return(err_rpt(errno,"Reading blocksize.")); } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &auobf) < 0) { return(err_rpt(errno,"Reading output audio buffer info.")); } if (ioctl(fd, SNDCTL_DSP_GETISPACE, &auibf) < 0) { return(err_rpt(errno,"Reading input audio buffer info.")); } printf("\nDSP details ................\n"); printf(" capabilites = 0x%09X\n formats = 0x%09X\n",caps,fmts); printf(" blocksize = %d\n", blksize); printf("\nDSP Capability revision level %d\n",caps&255); printf(" %s duplex operation (simultaneous read/write)\n", (caps&DSP_CAP_DUPLEX)?"Supports":"Does not support"); if (caps&DSP_CAP_REALTIME) printf(" Supports RealTime capability.\n" ); if (caps&DSP_CAP_BATCH) printf(" Has batch facilities (buffers) which may cause timing problems etc.\n"); if (caps&DSP_CAP_COPROC) printf(" Has a Co-Processor\n"); printf(" %s SETTRIGGER operation.\n", (caps&DSP_CAP_TRIGGER)?"Supports":"Does not support"); printf("\nDSP Formats supported are :-\n"); if (fmts&AFMT_MU_LAW) printf(" Mu_Law "); if (fmts&AFMT_A_LAW) printf(" A_Law "); if (fmts&AFMT_IMA_ADPCM) printf(" IMA_ADPCM "); if (fmts&AFMT_U8) printf(" U8 "); if (fmts&AFMT_S16_LE) printf(" S16_LE "); if (fmts&AFMT_S16_BE) printf(" S16_BE "); if (fmts&AFMT_S8) printf(" S8 "); if (fmts&AFMT_U16_LE) printf(" U16_LE "); if (fmts&AFMT_U16_BE) printf(" U16_BE "); if (fmts&AFMT_MPEG) printf(" MPEG "); printf("\n\n"); printf("Fragment details Output.. Input..\n"); printf(" total fragments %4d %4d\n", auobf.fragstotal,auibf.fragstotal); printf(" available %4d %4d\n", auobf.fragments,auibf.fragments); printf(" fragment size %5d %5d\n", auobf.fragsize,auibf.fragsize); printf(" bytes available %6d %6d\n\n", auobf.bytes,auibf.bytes); } do_mix(fd,dev) int fd; char *dev; { int devmask,recmask,sources,stereodevs,capabilities; int i,n; char buf[130]; char *devname[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; int level[SOUND_MIXER_NRDEVICES]; struct mixer_info Mix_Info; if (ioctl(fd, SOUND_MIXER_INFO, &Mix_Info) < 0) { err_rpt(errno,"Getting mixer_info details."); Mix_Info.id[0]=Mix_Info.name[0]=0; } if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { return(err_rpt(errno,"Reading Mixer Channels.")); } if (devmask==0) { return(err_rpt(ENODEV,"Mixer has no Channels!")); } if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) { return(err_rpt(errno,"Reading Recording Mask.")); } if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &sources) < 0) { return(err_rpt(errno,"Reading Recording Devices.")); } if (ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) < 0) { return(err_rpt(errno,"Reading Stereo Devices.")); } if (ioctl(fd, SOUND_MIXER_READ_CAPS, &capabilities) < 0) { return(err_rpt(errno,"Reading Mixer Capabilities.")); } printf("MIXER DETAILS ......................\n"); printf(" Mixer Id = %s\n Name = %s\n",Mix_Info.id,Mix_Info.name); printf(" devmask = 0x%09X\n recmask = 0x%09X\n",devmask,recmask); printf(" sources = 0x%09X\n stereodevs = 0x%09X\n",sources,stereodevs); printf("MIXER capabilities = 0x%09X\n",capabilities); if (capabilities & SOUND_CAP_EXCL_INPUT) printf(" Only one sound source can be selected at a time.\n"); printf("\nMIXER (%s) has following channels, set as :-\n",dev); for (i=0; i>8)&255); } else { printf(" "); } printf("%9s ", (recmask & (1< */ #include "config.h" #define VERSTR "%s Ver. %s Ncurses based Digital Sweep Generator" extern int vflg,dflg,vikeys; extern char *sys; extern char dac[]; /* name of output device */ extern int DAC; extern unsigned int samplerate; /* Samples/sec */ extern unsigned int stereo; /* stereo mono */ extern unsigned int afmt; /* format for DSP */ extern int Bufspersec; /* Number of Buffers per sec */ extern int Nfragbufs; /* number of driver buffers */ extern int fragsize; /* size of driver buffer fragments */ extern int fragsamplesize; /* size of fragments in samples */ extern int resolution; /* 1 = 1Hz resolution, 10 = 0.1HZ, extern int LWn; /* number of specified loadable waveforms */ extern char **LWaa; /* array of specifed loadable waveform /* Sweeping channel.... */ extern char wf[32]; /* waveform type */ extern unsigned int freq; /* signal frequency */ extern int ratio; /* used in pulse, sweep etc */ extern int Gain; /* Amplification factor */ /* Swept channel..... */ extern char wf2[32]; /* waveform type */ extern unsigned int freqF, freqT; /* low and upper freq of sweep */ extern unsigned int freqC; /* centre freq and deviation of sweep */ extern int frdev; extern int Gain2; /* Amplification factor */ siggen-2.3.10/siggen.html0000600000175000017500000002422111011653563013653 0ustar jjfamily Signal Generation tools for Linux and /dev/dsp

Signal Generation tools for Linux and /dev/dsp


Jim Jackson <jj@franjam.org.uk>

SIGGEN
Release 2.3.10 As with all software: there just maybe bugs

What are the programs?

This is a set of tools for imitating a laboratory Signal Generator, generating audio signals out of Linux's /dev/dsp audio device. There is support for mono and/or stereo and 8 or 16 bit samples. The basic waveform sample generation code is in the file generator.c, the functions here can be added to other programs fairly easily.

The current version can be downloaded from here http://www.comp.leeds.ac.uk/jj/linux/siggen.tgz.

This is a bug fix release.

2.3.10 Release: Paul Martin & Jens Peter Secher (Debian siggen package maintainer), reported problems with swept waveforms. There was an integer overflow problem in some circumstances - usually when using the x10 or x100 options.

Also this release changes the config file name from the old sound.conf to siggen.conf . Users with existing files can do:

  cd ~
  ln -s .sound.conf siggen.conf
 
as root

  cd /etc
  ln -s sound.conf siggen.conf

or simply copy the files

There should also be less warnings now!

2.3.9 Release: Lukas Loehrer reported a problem with writing raw sound files, and Mark Shimonek reported a bug and fix with setting the DSP device.

Several of the programs below are front ends for using the generator functions, mixing the generated outputs and playing them on /dev/dsp. None of the generation programs control the mixer - use your favourite mixer program or use the simple mixer 'smix' which I have included here.

soundinfo A program to display some of the programming capabilities of the sound system support for the mixer device /dev/mixer and the DSP device /dev/dsp. Can easily be changed if the mixer and dsp devices are called something else. Also shows some of the ioctl calls in action :-).\   Further info on your kernel's sound card configuration is given by 'cat /dev/sndstat'.
sgen is a command line signal generator where details are specified from the command line for generating sine, cos, square, triangle, sawtooth, pulse, noise waves. Frequency, sample rate, relative amplitude etc can be specified thru' command line options. The signal is played continuously until the program is stopped. There are options to save the basic raw digital samples raw to file or to a WAVE format file.
swgen is a command line sweep generator. Both the sweeping and swept waveforms can be specified, along with the sweeping frequency and the swept frequency range. Otherwise similar to sgen above.

siggen an Ncurses screen based Signal Generator for 2 seperate channels. On stereo audio cards the 2 channels are played on seperate outputs. On mono cards the 2 channels are digitally mixed onto the one output. Type of waveform, frequency, amplitude, sample rate etc are specified/changed via a screen menu. This is version 2. It plays continuously. Changes to parameters take effect (nearly) immediately. This version is pretty CPU intensive.
sweepgen an Ncurses screen based Sweep generator (see swgen above). It is like siggen. Changes to parameters take effect (nearly) immediately.
tones a command line program to generate several successive tones of varying freq., and optional differing waveforms, durations and intensities.\   The sequence of tones can be either played once (the default), or repetitively or the samples can be written to a file in raw or WAV format. This could make the basis of an auto-dialer for tone phones.\   Check out README.tones and the tones.eg directory for some examples of using the tones program.

smix a simple command line program for getting and setting the mixer settings. (Eee by gum, yet another mixer, yawn).
fsynth an Ncurses based "fourier" synthesis "realtime" generator.

Compiling and installing

You will need the ncurses library and header files. You will need sound card support compiled into your kernel. You can build some of the programs, tones sgen and swgen, without soundcard support. These programs then can be used to generate raw data or WAV files. You can also compile these programs under other OSes than Linux, e.g. Sunos 4.1.

Edit the configuration file config.h, to set the options/defaults you require. The defaults assume compilation under Linux with soundcard support. The file has ample comments and should be self explanatory. If anyone wants to suggest changes for building under other OSes then let me know and I'll inlcude the changes.

Check out the Makefile and edit anything that is wrong for your system. The ncurses library is assumed to be in normal library 'path' and the ncurses include file is assumed to be in either /usr/include/curses or /usr/include/ncurses/curses . If not, edit as appropriate. Just type 'make' to make the programs.

Don't set -Wall in the makefile, the results will be deeply embarassing to yours truly :-)

All the programs support optional interrogation of a common set of configuration files. See CONFIG.FILES for details.

Type 'make sysinstall' to install the programs into /usr/local/bin and the man pages into /usr/local/man/man1. Type 'make localinstall' to install into $HOME/bin and $HOME/man/man1. If none of these are ok for you then copy manually or edit the Makefile. Edit the setting of variable PROGS to customise which programs you install, e.g. you may not wish to install yet another mixer program so delete smix from the list.

These programs have been tested on on various versions of Linux from Kernels 2.0.36 - 2.6.22, and on distributions from RedHat et al., Debian and Ubuntu. Seems to work with ALSA or OSS, and I have reports of it porting to FreeBSD easily. Compiled with no sound card support, the command line utilities should work for creating sound files on most *nix OSes.

Distribution and Copying

Distribution of this package is covered by the terms of the GNU General Public License, version 2. See the file COPYING for further details. These programs are Copyright (c) 1996-2008 Jim Jackson & contributors.

Jim Jackson     <jj@franjam.org.uk>

HomePage http://www.comp.leeds.ac.uk/jj



This document was generated using AFT v5.095

siggen-2.3.10/scfio.doc0000600000175000017500000001713710404121121013274 0ustar jjfamily SCFIO - some routines for displaying and inputing Text, Integers, ----- decimal fractions, and selecting from a choice list. These routines are curses/ncurses based. (c) 1997,1998 Jim Jackson jj@franjam.org.uk [These functions are copyright under the GNU Public License - see the file - COPYING.] Introduction ------------ These are functions, structures and macros that allow screen display and input of lines of text, integer values, fixed decimal point values, and to select one of a list of options. In a lot of input routines the calling program effectively relinquishes program control until the user has entered the data and pressed some recognised termination key that ends the input which causes the function to return to the calling program. These functions use a structure to hold details of a field and its current state, and the functions action a KEY on the field, updating the field value and redisplaying if necessary. This allows the calling program to action keys as pressed and do other things while waiting for the next key. The calling program also has access to the fields value at any time and hence can intervene to expand abbreviations, do searches, do value checking, move to a new field etc etc. The SCField structure (see scfio.h) holds, among other things, information about the X,Y co-ordinates of the start of the field on the screen, the width in chars of the field, what type of field it is, what screen attribute to use when displaying the field, and a pointer to the data for the field. However functions and macros are provided so that the internal details can be ignored and a few simple functions only can be used. One of the side effects of this scheme is that with the state of input being recorded in the SCField structure, moving from one field to another brings you to the same position in the field as you were when you were last there. Using the functions ------------------- Only scfio.h and scfio.c are required. It may be best to copy these into the directory in which your C programs are. Any program using these functions, must #include "scfio.h" and link in scfio.o to the program as well as linking in the curses/ncurses library. Typically a final linking would be gcc prog.o scfio.o -lcurses Configuration ------------- There is only one compilation configuration option at the moment. If CLOSED_FIELDS is defined in scfio.h, or by defining it in the compilation line, then the LEFT and RIGHT arrows key will be actioned at all times in integer and string fields, even if the cursor is at the start or end of the field. Of course the cursor will not move, but the key functions will return -1 to show that the arrow keys were actioned. If CLOSED_FIELDS is not defined then at the start and end of the fields the LEFT and RIGHT arrow keys respectively are not actioned, and hence the key functions will return their values. If the calling code processes for any returned arrow keys (e.g. for moving to previous next field) then one gains the effect of moving thru' fields, from one field to another by using the arrow keys. The Main Functions ------------------ struct SCField *newfield(int type,int att,int COL,int ROW, int W,data *D,int id,int xtra) This function creates a new struct SCField, and initialises the structure with the given information about the field: int type is the type of field this is e.g. SCF_integer, SCF_string, SCF_option. Various flags can be added in to the type e.g. SCF_string+SCF_fixed for a fixed value text string. see scfio.h for a full list of values and a description. int att the attribute to be used when displaying the field on the screen see ncurses for details of screen attributes int COL the column and row positions for the start of the field int ROW on the screen. Positions start at 0. int W the width (number of character positions) of the field on the screen. data *D A pointer to integer, char[], etc that is the data for the field. If D is NULL then the correct data type will be created and the correct ptr used. If a string variable is created it will correctly hold W characters. For an SCF_option type D is char **, and it points to an array of strings defining the options allowed, with the end of the array indicated by a NULL ptr. For an SCF_option type the data pointer MUST be present and cannot be auto-created ! int id An optional parameter that can be used to make a field part of a group of fields sharing a common id or somesuch scheme. Usually not used and set to 0. int dp Integers can be displayed as decimal fractions with a fixed number of decimal places. This is the number of decimal places to display. The data is stored as an int, even though it is displayed as a decimal! For pure integers this will be 0. The function does some checking on the given parameters and if it can create the structure and initialise correctly it does so and returns a pointer to the structure. If it cannot, then it returns a NULL pointer. putfield(struct SCField *SP) This function displays the field defined by *SP on the screen. However it doesn't do a screen refresh(), this must be done by the calling program. This allows lots of successive putfield's to be done followed by a single refresh() to update the display. int actfield(int k, struct SCField *SP) This function actions the key value k on the field defined by *SP. Any new value causes the display to be correctly updated. If the key value is recognised and has an action then actfield returns -1. If the key value is not recognised and has done nothing the value k is returned. See below for a list of the key values that are recognised for different types of fields. int GetInt(struct SCField *SP) returns the current integer value of data in the SCField of type SCF_integer double GetFrac(struct SCField *SP) takes the current integer value of an SCF_integer type field, and divides it by 10^dp to create the exact fractional value as displayed in the field. char *GetStr(struct SCField *SP) returns a pointer to the string data for the SCField of type SCF_string char *GetOption(struct SCField *SP) returns a pointer to the current selected string option of the SCField of type SCF_option. Key Actions ----------- Integer fields: Digits 0-9 cause numeric entry, in like manner to a cash till, numbers entry from the right pushing previous digits leftwards. DEL and Backspace, delete the right most digit and move rest of digits rightwards UP arrow and DOWN arrow, increment and decrement the number by one String fields: Printable ASCII characters insert themselves, and push all chars to right of cursor one space rightwards. LEFT and RIGHT arrow, move the cursor left and right one space. DEL and Backspace delete the char to the left of the cursor and move all char to right of cursor one space leftwards. HOME moves cursor to start of string END moves cursor to end of string Option fields: UP and DOWN arrow select the previous and next option TAB and Space select the next option HOME selects the first option END selects the last option Examples -------- Several example programs are present in the distribution. See ftch.c and invoice.c for exmaples. There are lower level functions in scfio.c that are available to be used by the more adventurous - but I can't be too bothered commenting on those. Interested parties should look at scfio.h first then at scfio.c siggen-2.3.10/tonesgen.c0000600000175000017500000005431011011656637013506 0ustar jjfamily/* tonesgen.c * Parsing and playing of tones commands for "tones" program * Jim Jackson Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* History................... * * 18May99 Fixed mixing bug, and added a non-auto scale mode, where * mixing is absolute and it is upto the user to make sure * mixing doesn't cause the final output to clip by going above * 0dB level. * 13May99 Added Mark E. Shoulson's code to allow attenuation factors * in dB - i.e. 1000@-10 means 1KHz at -10dB * 23Feb98 made all samples be 16 bit, with 8 bit conversion when writing * to final audio buffer. * 20Feb98 Added recognition of musical notes format e.g. G3 for G * in 3rd octave, A#2 for A# in second octave. Octave '0' * runs from C at 33Hz to C at 65Hz * 8Sep97 split tones into 2 parts - this is the tones generation stuff * tones.c is all the preamble etc. * * Problems: * */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "wavsubs.h" #define CHAN_SEPERATOR(X) (X==',') #define ATT_START(X) (X=='@') /* defines the frequencies for basic musical notes - these are * integers storing the bottom octave freqs x 1000 */ /* A A# B B# C C# D D# */ int Notes[]={ 55000, 58270, 61735, 32703, 32703, 34649, 36709, 38892, 41204, 43654, 43654, 46250, 49000, 51913, }; /* E E# F F# G G# */ /* YEAH I know there is no E# and B# but by equiv'ing them to * frequencies for F and C it makes decoding from the table simpler. * Index into table is twice the letter-'A' and add one if a '#' * This means that E# gets decoded but produces F */ /* We hold data for a number of channels (voices or generators) in arrays * indexed by the channel number. This is done so that we can preserve * waveform integrity when we have to generate long tones over several * fragment buffers! (see the doTomeCmd() function) * Each generator has an assigned waveform, names and 1Hz samples * and a pointer into the sample space of the next sample to play. * * The arrays get initialised by init_samples(), and updated when waveforms * get changed. New waveforms can be specified for all channels, * or on channel by channel basis. */ char **WaveFormName=NULL; /* array of Current waveform name */ char **WaveForm=NULL; /* array of Current waveform samples */ int *CurSample=NULL; /* array of indices of next samples in WaveForm */ char **WavForms=NULL; /* Array of valid names for waveforms */ char **WavBufs=NULL; /* 1 Hz samples of all valid waveforms */ char *Silence; /* Silence waveform samples */ /* These values are setup by a call to init_samples() - see below. */ int samplerate=0, /* Samples/sec */ afmt=-1, /* Format of samples, 8bit or 16bit */ channels=0, /* number of generators */ stereo=-1; /* Mono or stereo */ double def_db=0; int BuffSize=0; /* size of buffer to use */ int FD; /* File Descriptor for writing samples to */ FILE *FO; /* and FILE * */ /* --------------------------------------------------------- */ short int *Buff; /* Actual sample buffer but in ints even for 8 bit */ int Buffsamples=0; /* number of samples per buffer */ unsigned int samples=0; /* count of number of samples written * since init_samples() called * returned by getsamples() */ unsigned int Tms; /* period in millisecs for each tone */ unsigned int Nt; /* number of samples for Tms */ /* --------------------------------------------------------- */ int GenErr=0; /* like errno, records status of last tonegen * operation */ #define ERR_NOMEM 1 /* No memory */ #define ERR_NOWAV 2 /* Unknown Waveform */ #define ERR_BADPAR 3 /* Bad parameter */ char GenErrStr[130]; /* Explanatory message for GenErr */ #define SetErrStr(S) strncpy(GenErrStr,S,128) /* --------------------------------------------------------- */ extern int vflg,Abs_Level; FILE *fWAVopen(); char *loadWavFile(); #define VERBOSE (vflg>1) #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) #define IS16BIT (afmt==AFMT_S16_LE) /* getGenErrStr() return the error string for the last recorded error */ char *getGenErrStr() { return(GenErrStr); } /* init_samples(fo,fdo,N,S,F,St,Ch,&Wn) initialise the generation variables etc. * So that we don't need to specify these again - store them in local * static variables, and initialise the 1Hz sample buffers. * We always generate 16 bit samples and convert to 8 bit on output if nec. * * fo is output FILE * or NULL if writing to a device * fdo is output file/device number, * N is buffer size to use in bytes, * S is sample rate * F is sample format (8 or 16 bit) * St is 0 for mono, 1 for stereo * Ch is number of generating channels to allow * *Wn is extra no. of entries to leave in Waveform arrays for loadable waveforms * it is updated by number of waveforms generated internally. */ init_samples(fo,fdo,N,S,F,St,Ch,Wn) FILE *fo; int fdo,N,S,F,St,Ch,*Wn; { int i; char *p,**aa; GenErr=samples=0; SetErrStr("OK"); /* calculate size of waveform name array and waveform sample array * This is Wn + number of waveforms that the internal generator code * creates + 1 for the NULL terminator. */ aa=(char **)getWavNames(); for ( i=0; aa[i]!=NULL; i++) { (*Wn)++; } /* Inc Wn for generator waves */ /* now allocate waveform arrays for Wn waveforms.... */ if (WavForms!=NULL) free(WavForms); if (WavBufs!=NULL) free(WavBufs); WavForms=(char **)malloc(((*Wn)+1)*sizeof(char *)); WavBufs=(char **)malloc(((*Wn)+1)*sizeof(char *)); if (WavForms==NULL || WavBufs==NULL) return(ENOMEM); for (i=0; i<=*Wn; i++) { WavBufs[i]=WavForms[i]=NULL; } if (i=genAllWaveforms(&WavForms,&WavBufs,1,S,AFMT_S16_LE)) return(i); if ((i=setwaveform("off",&Silence,NULL))) return(i); if (Buff!=NULL) free(Buff); /* if 8bit then double buffer size 'cos we do all stuff 16bit internally */ if ((Buff=malloc(N<<(F==AFMT_U8)))==NULL) { SetErrStr("Cannot allocate Play Buffer"); return(GenErr=ERR_NOMEM); } if (WaveFormName!=NULL) free(WaveFormName); WaveFormName=(char **)malloc(Ch*sizeof(char *)); if (WaveForm!=NULL) free(WaveForm); WaveForm=(char **)malloc(Ch*sizeof(char *)); if (CurSample!=NULL) free(CurSample); CurSample=(int *)malloc(Ch*sizeof(int)); if (WaveFormName==NULL || WaveForm==NULL || CurSample==NULL) { SetErrStr("Cannot allocate Generator Arrays"); return(GenErr=ERR_NOMEM); } FO=fo; FD=fdo; BuffSize=N; samplerate=S; afmt=F; stereo=St; channels=Ch; def_db=0; Tms=0; Buffsamples=(N>>stereo)>>(afmt==AFMT_S16_LE); /* calc number of samples * in buffer */ for (i=0; i 0) && (W->samplerate != SR)) { e=EINVAL; if (vflg) printf("Samplerate is incorrect %d != %d\n",SR,W->samplerate); } if ((afmt>0) && (W->afmt != afmt)) { e=EINVAL; if (vflg) printf("Sample format is incorrect %d != %d\n",afmt,W->afmt); } if ((st > -1) && (W->stereo != st)) { e=EINVAL; if (vflg) printf("Number of channels is incorrect %d != %d\n",st+1,(W->stereo)+1); } if ((SN > 0) && (W->samples != SN)) { e=EINVAL; if (vflg) printf("Number of samples is incorrect %d != %d\n",SR,W->samples); } } if (e==0) { if ((bf=malloc(SN<<(afmt==16)))!=NULL) { if ((n=wavread(f,W,bf,SN<<(afmt==16)))!=SN) { e=EINVAL; if (vflg) printf("Number of samples read is incorrect %d != %d\n",SR,n); free(bf); } } else e=ENOMEM; } free(W); fclose(f); return((e)?NULL:bf); } /* setwaveform(s,WFs,WFN) search for string s in list of waveform names * and if found set up *WFs with sample space and *WFN as name. * Return 0 if all ok * else return error number and set up GenErr and GenErrStr */ setwaveform(s,WFs,WFN) char *s; char **WFs,**WFN; { int i,n; char *p; p=(s==NULL)?"":s; /* Zero length string selects first waveform */ n=strlen(p); for ( i=0; WavForms[i]!=NULL; i++) { if (chkword(2,WavForms[i])) { if (WFs!=NULL) *WFs=WavBufs[i]; if (WFN!=NULL) *WFN=WavForms[i]; return(0); } } sprintf(GenErrStr,"No such waveform: \"%s\".",p); return(GenErr=ERR_NOWAV); } /* getsamples() return number of samples written since init_samples * called. */ unsigned int getsamples() { return(samples); } /* flush_samples() to write enough silence to fill the current * kernel buffer fragment, so we don't get spurious sounds. */ flush_samples() { int n; int cp=0; if (samplerate==0) return(0); if ((n=samples%Buffsamples)) { n=Buffsamples-(samples%Buffsamples); newsamples(Buff,Silence,&cp,n,10000); writesamples(Buff,n); } samplerate=0; return(0); } /* newsamples(bf,wav,N,F,G) create N new samples from waveform wav * at freq F and store in buffer bf. *cp is the 'phase' pointer * for selecting next sample from wav. Scale samples * by G/10000. BEWARE of G>32000 because of overflow probs. */ newsamples(bf,wav,cp,N,F,G) short int *bf; short int *wav; int *cp,N,F,G; { int i,n,t; short int *vbp; /* all sorts of things can go wrong in this code * it is assumed that the calling code calls with sensible * parameters */ vbp=bf; if (G>32000) G=32000; for (i=0; i32767)?32767:((t<-32768)?-32768:t)); /* clipping */ *cp=(*cp+F)%samplerate; } } /* addsamples(bf,wav,cp,N,F,G,L) add N new samples from waveform wav * at freq F into abuffer bf, of 'level' L, *cp is the 'phase' * pointer for selecting next sample from wav. scale * new samples by G/10000. Like G, L is scaled by 10000 * returns the mixing "level" index. */ addsamples(bf,wav,cp,N,F,G,L) short int *bf; short int *wav; int *cp,N,F,G,L; { int i,n,t,NL; short int *vbp; /* all sorts of things can go wrong in this code * it is assumed that the calling code calls with sensible * parameters */ vbp=bf; if (L) { /* with an auto-'level' we are autoscaling */ for ( NL=L+G ; (L+G)>32767; L>>=1, G>>=1) { } /* this keeps the arith to 32 bits */ for (i=0; i32767)?32767:((t<-32768)?-32768:t)); /* clipping */ *cp=(*cp+F)%samplerate; } } else { /* without an auto-'level' we are doing absolute mixing */ for (NL=i=0; i32767)?32767:((t<-32768)?-32768:t)); /* clipping */ *cp=(*cp+F)%samplerate; } } return(NL); } /* doToneCmd(s) interpret tone command in string s * * if *s is alphanumeric then it changes waveform or is a directive, * it can be a comma * separated list of waveforms to setup the different channels. * if *s is numeric and default tone period not set then sets tone period * else it is a tone specification * N a single freq. to play for default time period * N:t a single freq. played for t millisecs (overrides def. time period) * N1,N2,... mix freqs N1,N2 etc and play the mix for default time period * N1,N2,...:t as above but played for t millisecs * any of the above N can be replaced with N@db where db is number * of deciBells by which to amplify or attenuate that tone. * * e.g. 300,600@-20:500 play a mixed tone of 300Hz mixed with 600Hz * attenuated by 20dB for 500 millisecs. * * :t on its own sets the default time period to t millisecs * @db on its own sets the default dB level * * Directives currently are...... * * echo restofline outputs restofline to standard output * reset|resync resets sample pointers for all channels to 0 * forces known phase relationships * absolute|relative set absolute or relative amplitude mixing * * If a command starts with an alphabetic char. abd isn't one of above * and isn't a named waveform, then tones checks if there is a file * with the name and if so it opens it as a file of tones specifications. * When that file has been processed tones continues with where it is. */ doToneCmd(s) char *s; { char *p,*ss; int i,f,n,N,t,st,sCS; int Tt,T; GenErr=0; SetErrStr("OK"); for ( ; isspace(*s); s++) {} if (isalpha(*s) && isalpha(*(s+1))) { if (strncmp("echo",s,4)==0) { printf("%s\n",s+5); } else if (strncmp("reset",s,5)==0 || (strncmp("resync",s,6)==0)) { for (i=0; i='A' && n<='G') { n=(n - 'A')*2; (*s)++; if (**s == '#') { (*s)++; n++; } n=Notes[n]; if (isdigit(**s)) { n=((n<<((**s) - '0'))+500)/1000; (*s)++; if (vflg) printf(" (%dHz)\n",n); return(n); } } return(0); } /* docmdwaveform(s) parse string s as a waveform selection string * * either "waveform" selects all generators done * or "waveform,waveform,etc" sets waveforms sequentially done */ docmdwaveform(s) char *s; { char *p,c,bf[130]; unsigned char *wf,*wfn; int st; strcpy(bf,s); for ( s=bf, st=0; *s && st %s\n",fn,i,p,getGenErrStr()); } } } } doline(s) char *s; { int i,n; char **aa[50]; for ( ; isspace(*s); s++) {} if (*s && *s!='#') { n=parse(s,aa,'\0'); for (i=0; i #include #include #include #include #include #include #include #include #include #include #include #include #include "sweepgen.h" #define MAXPRM 32 #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) int vflg,dflg,vikeys; int resolution; /* Freq. resolution for signal generation * 1 for 1Hz res ; 10 for 0.1Hz res; * 100 for 0.01Hz res */ int DAC; /* File Handle for DSP */ unsigned int samplerate; /* Samples/sec */ unsigned int stereo; /* stereo mono */ unsigned int afmt; /* format for DSP */ int Bufspersec; /* number of sounds fragments per second */ int Nfragbufs; /* number of driver frag buffers */ int fragsize; /* size of driver buffer fragments */ int fragsamplesize; /* size of fragments in samples */ int LWn; /* number of specified loadable waveforms */ char **LWaa; /* array of specifed loadable waveforms */ /* channel 1 the sweeping signal ... */ char wf[32]="sawtooth"; /* waveform type */ unsigned int freq=1; /* signal frequency */ int ratio=-1; /* used in pulse, sweep etc */ int Gain=1000; /* Amplification factor */ /* channel 2 the swept signal ... */ char wf2[32]="sine"; /* waveform type */ unsigned int freqF=500; /* signal low frequency */ unsigned int freqT=1500; /* signal high frequency */ unsigned int freqC=1000; /* signal centre frequency */ int frdev=500; /* signal deviation frequency */ int ratio2=-1; /* used in pulse, sweep etc */ int Gain2=1000; /* Amplification factor */ int phase=0; /* phase difference of chan2 from chan1 */ char *sys; char *configfile; char dac[130]; help(e) int e; { char **aa; fprintf(stderr,VERSTR,sys,VERSION); fputs("\nUsage: \n 1: sweepgen [flags] [waveform [freq [param]]]\n",stderr); #ifdef HAVE_DAC_DEVICE fprintf(stderr,"Defaults: SINE wave swept by SAWTOOTH, output to %s, %d samples/sec,\n", DAC_FILE,SAMPLERATE); fputs(" 16 bit stereo samples if possible, else 8 bit and/or mono.\n",stderr); #else fprintf(stderr,"Defaults: SINE wave swept by SAWTOOTH, %d samples/sec,\n",SAMPLERATE); fputs(" 16 bit stereo samples. Must be used with -o or -w option.\n",stderr); #endif fputs("Valid waveforms are:",stderr); for ( aa=(char **)getWavNames(); *aa; aa++ ) fprintf(stderr," %s",*aa); fputs("\n",stderr); fprintf(stderr,"Default Config files are \"%s\", \"$HOME/%s\" and\n\"%s\", searched in that order.\n", DEF_CONF_FILENAME, DEF_CONF_FILENAME, DEF_GLOBAL_CONF_FILE); fputs("flags: -s samples generate with samplerate of samples/sec\n",stderr); fputs(" -8/-16 or -b 8|16 force 8 bit or 16 bit mode.\n",stderr); fputs(" -1 force mono - swept frequency output only\n",stderr); fputs(" -2 force stereo - swept freq on one chan, sweeping on other chan.\n",stderr); fputs(" -NB n Number of Buffers to create is n, def. is 3\n",stderr); fputs(" -BPS n Number of Buffers to play per sec, def. is 15\n",stderr); /* fputs(" -load wave_file load waveform from wav_file\n",stderr);*/ fputs(" -res n n=1, 0.1 or 0.01 - frequency resolution\n",stderr); return(e); } /* main * */ main(argc,argv) int argc; char **argv; { unsigned int v[MAXPRM],maxv,i,j,k,l,m,n,N; FILE *f; char *p,bf[130]; int c; unsigned int t; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; samplerate=0; afmt=AFMT_QUERY; Bufspersec=0; Nfragbufs=0; vflg=dflg=0; stereo=-1; resolution=0; while (argc && **argv=='-') { /* all flags and options must come */ n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (chkword(1,"samplerate")) { if (argc && isdigit(**argv)) { samplerate=atoi(*argv++); argc--; } } else if (chkword(2,"NB")) { if (argc && isdigit(**argv)) { Nfragbufs=atoi(*argv++); argc--; } } else if (chkword(3,"BPS")) { /* Buffers played per second - defines size */ if (argc && isdigit(**argv)) { Bufspersec=atoi(*argv++); argc--; } } else if (chkword(2,"16")) { afmt=AFMT_S16_LE; } else if (chkword(1,"bits")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i==8) afmt=AFMT_U8; else if (i==16) afmt=AFMT_S16_LE; else exit(err_rpt(EINVAL,"must be '-b 8' or '-b 16'.")); } else if (chkword(1,"A")) { if (argc && isdigit(**argv)) { Gain=atoi(*argv++); argc--; } } else if (chkword(3,"load")) { /* load a waveform */ if (argc) { LWaa[LWn++]=*argv++; argc--; } /* waveform file name */ } else if (chkword(3,"resolution")) { /* set freq generation resolution */ if (argc) { if ((resolution=set_resolution(*argv++))==0) { exit(err_rpt(EINVAL,"bad resolution value, must be 1, 0.1 or 0.01")); } argc--; } } else { /* check for single char. flags */ for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='1') stereo=0; else if (*p=='2') stereo=1; else if (*p=='8') afmt=AFMT_U8; else if (*p=='d') dflg=1; else if (*p=='v') vflg++; else { *bf='-'; *(bf+1)=*p; *(bf+2)=0; exit(help(err_rpt(EINVAL,bf))); } } } } if (argc) { strncpy(wf,*argv++,32); wf[31]=0; argc--; /* waveform type */ if (argc) { freq=atoi(*argv++); argc--; if (argc) { ratio=atoi(*argv++); argc--; } if (argc) exit(help(err_rpt(EINVAL,"Too many parameters"))); } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (samplerate==0) { samplerate=atoi(get_conf_value(sys,"samplerate",QSAMPLERATE)); } if (stereo==-1) { stereo=atoi(get_conf_value(sys,"channels","1")); if (stereo) stereo--; } if (Nfragbufs==0) { Nfragbufs=atoi(get_conf_value(sys,"fragments",QDEFAULT_FRAGMENTS)); } if (resolution==0) { resolution=set_resolution(get_conf_value(sys,"resolution",DEFAULT_RESOLUTION)); if (resolution==0) { exit(err_rpt(EINVAL,"bad resolution value, must be 1, 0.1 or 0.01")); } } if (Bufspersec==0) { Bufspersec=atoi(get_conf_value(sys,"buffspersec",QDEFAULT_BUFFSPERSEC)); } if (afmt==AFMT_QUERY) { afmt=atoi(get_conf_value(sys,"samplesize",QAFMT_QUERY)); } strncpy(dac,get_conf_value(sys,"dacfile",DAC_FILE),sizeof(dac)-1); vikeys=atoi(get_conf_value(sys,"vi_keys",QVI_KEYS)); /* if no format specified then try 16 bit */ i=afmt; n=stereo; if ((DAC=DACopen(dac,"w",&samplerate,&i,&n))<0) { exit(err_rpt(errno,dac)); } if (((afmt!=AFMT_QUERY) && (i!=afmt)) || ((stereo!=-1) && (n!=stereo))) { exit(err_rpt(EINVAL,"Sound card doesn't support format requested.")); } afmt=i; stereo=n; if ((fragsize=setfragsize(DAC,Nfragbufs,Bufspersec,samplerate,afmt,stereo))<0) { exit(err_rpt(errno,"Problem setting appropriate fragment size.")); } fragsamplesize=(fragsize>>(afmt==AFMT_S16_LE))>>(stereo); if (freq > samplerate/2) { fprintf(stderr,"%d Hz is more than half the sampling rate\n",freq); } if (vflg) { printf("%s %s bit samples being generated.\n", (stereo)?"Stereo, ":"Mono, ",(afmt==AFMT_S16_LE)?"16":"8"); printf("Samples scaled by a factor of %d/1000\n",Gain); printf("Playing at %d samples/sec\n",samplerate); printf("Frequency resolution is %.2fHz\n",1.0/resolution); printf("Buffer fragment size is %d bytes (%d samples). Aprox. %d millisecs.\n", fragsize, fragsamplesize, 1000*((fragsize>>(stereo))>>(afmt==AFMT_S16_LE))/samplerate); printf("Requested %d buffers/sec and have %d buffs/sec\n",Bufspersec, (samplerate+(fragsamplesize/2))/fragsamplesize); } WinGen(DAC); close(DAC); exit(0); } set_resolution(p) char *p; { char *s; int r; double d; d=strtod(p,&s); r=0; if (d==1.0) r=1; else if (d==0.1) r=10; else if (d==0.01) r=100; return(r); } siggen-2.3.10/smix.c0000600000175000017500000002466711011645640012650 0ustar jjfamily/* smix.c * Simple Linux Mixer controller * Jim Jackson Fri 16 Jun 1995 */ /* smix: (version 1) Nov 1996 based on the dos sb16 mixer...... smix: (version 1) Fri 16 Jun 1995 NAME: smix - Simple Linux Mixer controller SYNOPSIS: smix [-v] [-h] [-o file] [-i file] [command(s)] DESCRIPTION: Controls the Mixer settings from the command line parameter(s). The commands are detailed below, capitals showing the minimum abbreviation allowed. Upper or lower case can be used on the command line. All Volume settings are in range 0-100 (0 min, 100 max), but these are scaled to the mixers actual range, hence set volume may be slightly different. SHow outputs the settings of the mixer. This is the default if no command line parameters are given dev N or L,R sets mixer device 'dev' to volume N, or to seperate left and right stereo volume L,R If device doesn't support stereo settings then max of L,R is used. INput dev set the DSP input to be 'dev' or 'NOne' to turn inputs off Verbose makes the program output the settings after doing the commands Use '-' as a filename to indicate standard input. FLAGS: -state outputs details is a form that can used as the command line parameters to an smix command. This can be used to save the settings in a shell variable and then reset them. -h lists usage summary, which also lists the mixer devices and the possible input devices. -v verbose - outputs the results of commands. Same as Verbose above OPTIONS: -i file read commands from file -o file output to file file -m mixerdev mixer device to use -C configfile read configfile NOTES: BUGS: Any questions, suggestions or problems, etc. should be sent to Jim Jackson Email: jj@franjam.org.uk */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "mixer.h" #define PROGNAME "smix" #define EFAIL -1 #ifndef FALSE # define FALSE 0 #endif #ifndef TRUE # define TRUE !FALSE #endif #define nl puts("") #define option(b,a) ((n>=a)&&(strncasecmp(p,b,n)==0)) #define doshow(F) printvols(devmask,F) char mixname[130]; int mixer; /* Mixer File Descriptor */ char *outfile; char *infile; char *configfile; char *sys; int state; int vflg; int hflg; char *strupper(),*reads(),*sindex(),*tab(); FILE *fopen(); unsigned char readmixer(); main(argc,argv) int argc; char **argv; { int i,j,n,st; char fname[132],*p; FILE *fpr,*fpw; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; infile=outfile=NULL; mixname[0]=0; vflg=hflg=FALSE; state=FALSE; while (argc && **argv=='-') { n=strlen(p=(*argv++)+1); argc--; if (option("output",1)) { if (argc) { outfile=*argv++; argc--; } } else if (option("input",1)) { if (argc) { infile=*argv++; argc--; } } else if (option("Config",1)) { if (argc) { configfile=*argv++; argc--; } } else if (option("mixer",1)) { if (argc && **argv!='-') { strncpy(mixname,*argv++,sizeof(mixname)-1); mixname[sizeof(mixname)-1]=0; argc--; } } else if (option("state",1)) { state=TRUE; } else { for (; *p; p++) { if (*p=='h') hflg++; else if (*p=='v') vflg++; else { *fname='-'; *(fname+1)=*p; *(fname+2)=0; exit(err_rpt(EINVAL,fname)); } } } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (mixname[0]==0) { strncpy(mixname,get_conf_value(sys,"mixerfile",MIXER_FILE),sizeof(mixname)-1); mixname[sizeof(mixname)-1]=0; } if ((mixer=mixinit(mixname)) < 0) { exit(err_rpt(errno,mixname)); } if (hflg) exit(help()); if (vflg) printf("Mixer %s\n",mixname); if (outfile!=NULL) { if (strcmp(outfile,"-")==0) fpw=stdout; else if ((fpw=fopen(outfile,"w"))==NULL) { exit(err_rpt(errno,outfile)); } } else { fpw=stdout; } if (infile!=NULL) { if (strcmp(infile,"-")==0) fpr=stdin; else if ((fpr=fopen(infile,"r"))==NULL) { exit(err_rpt(errno,infile)); } } else { fpr=stdin; } if (infile!=NULL) { st=docmdfile(infile,fpr,fpw); /* do any command file first */ st+=docmds(argc,argv,fpw); } else if (argc) st+=docmds(argc,argv,fpw); else st+=docmdline("show",fpw); exit(st); } docmdfile(fn,f,fo) char *fn; FILE *f,*fo; { char bf[514],*p; while ((p=fgets(bf,512,f))!=NULL) { docmdline(bf,fo); } } docmdline(s,fo) char *s; FILE *fo; { int n,v; char *aa[64],c,*p,*r,*q; for ( ; *s && isspace(*s); s++) {} /* skip initial whitespace */ if (*s=='#') return(0); /* comment line - ignore */ for (n=0; *s; n++) { aa[n]=s++; for ( ; *s && !isspace(*s); s++ ) {} if (isspace(*s)) *s++=0; for ( ; *s && isspace(*s); s++) {} } docmds(n,aa,fo); } docmds(c,v,fo) int c; char **v; FILE *fo; { int i,st,n,d,dopr; char *p; for ( ; c; ) { n=strlen(p=*v++); c--; if (option("show",2)) doshow(fo); else if (option("verbose",1)) vflg++; else if (option("input",2)) { dopr=0; if ( c && ((d=isdev(p=*v))>=0 || option("none",2))) { v++; c--; if ( (d>=0) && IS_MIX_INPUT_DEV(d)==0 ) { fprintf(stderr,"%s is not a source device.\n",MIX_DEV_NAME(d)); } else { if ( SET_MIX_INPUT_DEV(d) < 0) { fprintf(stderr,"Couldn't set %s as recording source.\n", (d>=0)?(MIX_DEV_NAME(d)):"no device"); } if (vflg) dopr=1; } } else { dopr=1; } if (dopr) { if (sources) printvols(sources,fo); else fprintf(fo,"No source inputs active."); } } else if (option("all",3)) { if (c && isvol(*v)) { p=*v++; c--; doallvols(devmask,p,fo); } else doshow(fo); } else if ((d=isdev(p,n))>=0) { if (c && isvol(*v)) { p=*v++; c--; } else p=""; dovol(d,p,fo); } else { fprintf(stderr,"Command '%s' not recognised.\n",p); st=1; } } } isvol(s) char *s; { return(isdigit(*s) || (strncasecmp(s,"off",3)==0) || (strncasecmp(s,"full",4)==0)); } /* dovol(d,s) set mixer device d to volume specified by string s * s is an "NN" or "LL,RR", i.e. a numeric ascii string * or two num ascii strings for stereo left and right settings */ dovol(d,s,fo) int d; char *s; FILE *fo; { int lv,rv,n,dopr; char buf[130]; dopr=vflg; if (s!=NULL && *s) { if (strncasecmp(s,"off",3)==0) { lv=0; s+=3; } else if (strncasecmp(s,"full",4)==0) { lv=100; s+=4; } else { for ( lv=0; isdigit(*s); s++) { lv=lv*10+(*s-'0'); } } if (*s == ',' || *s == '/') { s++; if (strcasecmp(s,"off")==0) { rv=0; } else if (strcasecmp(s,"full")==0) { rv=100; } else { for ( rv=0; isdigit(*s); s++) { rv=rv*10+(*s-'0'); } } } else rv=lv; if (IS_MIX_DEV_STEREO(d)) n=(rv<<8)+lv; else n=(lv>rv)?lv:rv; if (SET_MIX_VALUE(d,n) < 0) { sprintf(buf,"Problem setting level of mixer channel %s.", MIX_DEV_NAME(d)); err_rpt(ENODEV,buf); } } else { dopr=1; } if (dopr) printvol(d,fo); } printvols(devs,fo) int devs; FILE *fo; { int i; for (i=0; i>8)&255); } else { fprintf(fo," "); } if (state) { fprintf(fo,"\n"); if (IS_MIX_SOURCE(d)) fprintf(fo,"INPUT %s\n",MIX_DEV_NAME(d)); } else { fprintf(fo,"%2s ", (IS_MIX_INPUT_DEV(d))? "*":""); fprintf(fo,"%3s ", (IS_MIX_SOURCE(d))? "<-":""); fprintf(fo,"\n"); } } } } help() { int i; printf("\nSet Linux Mixer from the command line - mixer device is %s\n\n",mixname); printf("Commands are :-\n"); printf(" Verbose or -v verbose mode, outputs results of actions\n"); printf(" DEV N or L,R sets DEV to N or left to L, Right to R\n"); printf(" where DEV can be :\n "); for (i=0; i='a') && (*i<='z')) *i-=d ; return(p); } /***DELNL***/ /* char *delnl(s) remove trailing nl from end of string s * return same pointer as given */ char *delnl(s) char *s; { char *p; if (s!=NULL && *s && *(p=s+strlen(s)-1)=='\n') *p=0; return(s); } siggen-2.3.10/README0000600000175000017500000000106207624013345012372 0ustar jjfamily SIGGEN ------ See the siggen.aft files for an overview (or the derived file siggen.html). If you aren't familiar with Almost Free Text (AFT) then, no problem, just more or less the file. It should be readable as ASCII text. There are manual pages for each utility. To read try nroff -man siggen.1 | less or install man pages into a suitable location and use man. Finally there is the source. Oh! There is a README.tones with info about the example directory (tones.eg) for the tones program. AFT homepage is http://www.maplefish.com/todd/aft.html siggen-2.3.10/tones.c0000600000175000017500000003411711011656627013016 0ustar jjfamily/* tones.c * generate and play tones for given period.... * Jim Jackson Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* History................... * * 17Mar06 Fixed Wav writing bug reported by Lukas Loehrer * 9Mar06 Fixed raw writing bug reported by Lukas Loehrer * Apr00 added loadable waveforms * 18May99 added absolute level mode. * 1Sep98 added configuration file(s) support * 18Jun98 Modified to compile with no sound card support etc and under SUNOS * 20Feb98 Added recognition of musical notes format e.g. G3 for G * in 3rd octave, A2# for A# in second octave. Octave '0' * runs from C at 33Hz to C at 65Hz * 9Sep97 Split out the tone spec. parsing and tone playing into * tonesgen.c * 8Sep97 Alter tones specification to be able to specify different * durations. i.e. t1,t2:ms. * Also start the change of generating technique to do sampling * 1Hz sample space for requisite number of samples. * --Aug97 Re-organise some of DAC routines out into DAC.c * 18Feb97 -f flag missing, added it * also added facility to be able to change wavform. A * non-numeric parameter will cause a change in waveform * for rest of tones. * Also still occasional noise after tones played - altered DSPend again! * 16Feb97 altered it so you can specify several freqs to be played together * by using punctuation of some sort to seperate freqs * e.g. 440,880 would play two freqs of 440Hz and 880Hz together * 13Feb97 Based on sgen, using generator.c - only mono version. * */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #define VERSTR "%s Ver. %s Tone Generator.\n" #define EFAIL -1 #define MAXPRM 32 #define MAXTONES 64 #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) int aflg,fflg,vflg,dflg,wfmt; int loopflg; int Abs_Level ; /* if set cancel auto-scale mode */ unsigned int stereo; /* stereo or mono mode */ unsigned int samplerate; /* Samples/sec */ unsigned int ratio; /* used in pulse, sweep etc */ unsigned int afmt; /* format for DSP */ unsigned int DSPbytecount; /* number of bytes sent to DSP */ int frag_size; /* size of a DSP buffer */ int channels; /* number of generating channels */ int Wn; /* number of allowed loadable waveforms */ int TWn; /* Total number of waveforms */ int LWn; /* number of specified loadable waveforms */ char **LWaa; /* array of specifed loadable waveforms */ char *sys,*outfile,*infile; char dac[130]; char *configfile; extern char *getGenErrStr(); help(e) int e; { char **aa; fprintf(stderr,VERSTR,sys,VERSION); fputs("\nUsage: tones [-s samplerate] [-8/-16|-b 8/16] [waveform] :T freq(s)\n\n",stderr); #ifdef HAVE_DAC_DEVICE fprintf(stderr,"Defaults: SINE wave, %d channels, output to %s, %d samples/sec,\n", DEF_TONES_CHANNELS,DAC_FILE,SAMPLERATE); fputs(" 16 bit mono samples if possible, else 8 bit.\n",stderr); #else fprintf(stderr,"Defaults: SINE wave, %d channels, %d samples/sec,\n", DEF_TONES_CHANNELS,SAMPLERATE); fputs(" 16 bit mono samples. Must be used with -o or -w option.\n",stderr); #endif fputs("\ Generates T millisecs of each frequency specified. Several freqs can be\n\ played together, e.g. 150,200,300. Relative amplitudes can be specified\n\ in dB e.g. 150@-6,200,300@-12. The channels option gives the maximum number\n\ of freqs. Each channel adds processing overhead to the generation process.\n\ Non-default specific durations maybe given e.g. 440,880:1000\n\ ",stderr); #if FALSE fputs("Generates tones of given frequencies for T millisecs each.\n",stderr); fputs("Several freqs can be played together by specifying a list of freqs\n",stderr); fputs("separated by ',', e.g. 150,200,300. relative amplitudes can be specified\n",stderr); fputs("by using the suffix @-dB after the freq.\n",stderr); fputs("The maximum number of frequencies which can be played together\n",stderr); fputs("is specified by the '-c channels' option. Each channel adds\n",stderr); fputs("processing overhead to the generation process.\n",stderr); fputs("A specific duration of N millisecs maybe given, overriding the default,\n",stderr); fputs("by appending ':N'\n",stderr); fputs("e.g. 150,300:250 plays 150Hz and 300Hz together for 250 millisecs\n",stderr); fputs(" 0:1000 plays one second (1000ms) of silence.\n",stderr); #endif fputs("Valid waveforms are:",stderr); for ( aa=(char **)getWavNames(); *aa; aa++ ) fprintf(stderr," %s",*aa); fputs(".\nand can be specified anywhere and affect all later tones.\n",stderr); fputs("flags: -f,-a force overwrite/append of/to file\n",stderr); fputs(" -o/-w file write samples to raw/WAVE file ('-' is stderr)\n",stderr); fputs(" -i file contents of file specify tones program ('-' is stdin)\n",stderr); fputs(" -load wave_file load waveform from wav_file\n",stderr); fputs(" -s samples generate with samplerate of samples/sec\n",stderr); fputs(" -c channels number of channels or voices\n",stderr); fprintf(stderr," -lw N number of loadable waveforms allowed - def %d\n",DEF_WN); fputs(" -loop N repeat play the tones N times.\n",stderr); fputs(" -l repeat play the tones ad nauseam.\n",stderr); fputs(" -v/-vv be verbose / be very verbose\n",stderr); fputs(" -8/-16 or -b 8|16 force 8 bit or 16 bit mode.\n",stderr); fputs(" -abs|-rel set absolute or relative amplitude control.\n",stderr); return(e); } /* main * */ main(argc,argv) int argc; char **argv; { unsigned int i,j,k,l,m,n,N; FILE *f,*fi; char *p,*fnm,bf[260],*omode; int fd,st; unsigned int t; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; outfile=infile=NULL; samplerate=0; afmt=AFMT_QUERY; channels=0; Wn=-1; LWn=0; LWaa=argv; stereo=0; loopflg=wfmt=frag_size=0; /* force mono mode */ Abs_Level=dflg=vflg=aflg=fflg=0; while (argc && **argv=='-') { /* all flags and options must come */ n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (chkword(1,"samplerate")) { if (argc && isdigit(**argv)) { samplerate=atoi(*argv++); argc--; } } else if (chkword(1,"output")) { /* specify output file */ if (argc) { outfile=*argv++; argc--; } /* output file name */ } else if (chkword(1,"input")) { /* specify input file */ if (argc) { infile=*argv++; argc--; } /* input file name */ } else if (chkword(3,"load")) { /* load a waveform */ if (argc && **argv!='-') { LWaa[LWn++]=*argv++; argc--; } /* waveform file name */ } else if (chkword(2,"lw")) { i=0; if (argc && **argv!='-') { i=atoi(*argv++); argc--; Wn=(i>0)?i:0; } } else if (chkword(3,"loop")) { /* specify loop option */ if (argc && **argv!='-') { loopflg=atoi(*argv++); argc--; } } else if (chkword(3,"absolute")) { /* absolute amplitude levels */ Abs_Level=1; } else if (chkword(3,"relative")) { /* relative amplitude levels */ Abs_Level=0; } else if (chkword(1,"wave")) { /* e.g. write WAVE format file */ if (argc) { outfile=*argv++; argc--; wfmt=1; } /* output file name */ } else if (chkword(2,"16")) { afmt=AFMT_S16_LE; } else if (chkword(1,"bits")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i==8) afmt=AFMT_U8; else if (i==16) afmt=AFMT_S16_LE; else exit(err_rpt(EINVAL,"must be '-b 8' or '-b 16'.")); } else if (chkword(1,"channels")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i<1) exit(err_rpt(EINVAL,"Must have 1 or more channels.")); channels=i; } else { /* check for single char. flags */ for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='8') afmt=AFMT_U8; else if (*p=='a') aflg=1; else if (*p=='f') fflg=1; else if (*p=='d') dflg=1; else if (*p=='l') loopflg=-1; else if (*p=='v') vflg++; else { *bf='-'; *(bf+1)=*p; *(bf+2)=0; exit(help(err_rpt(EINVAL,bf))); } } } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (samplerate==0) { samplerate=atoi(get_conf_value(sys,"samplerate",QSAMPLERATE)); } if (channels==0) { channels=atoi(get_conf_value(sys,"channels",QDEF_TONES_CHANNELS)); } if (Wn==-1) { Wn=atoi(get_conf_value(sys,"loadable_waveforms",QDEF_WN)); } if (afmt==AFMT_QUERY) { afmt=atoi(get_conf_value(sys,"samplesize",QAFMT_QUERY)); } strncpy(dac,get_conf_value(sys,"dacfile",DAC_FILE),sizeof(dac)-1); /* Now check if any input file to be read........ */ if (vflg) printf(VERSTR,sys,VERSION); fi=NULL; /* fi!=NULL if a command file is to be read */ if (infile!=NULL) { /* check for valid infile if specified */ if (strcmp(infile,"-")==0) { fi=stdin; infile="stdin"; } else if ((fi=fopen(infile,"r"))==NULL) { exit(err_rpt(errno,infile)); } } /* open the right device or output file............ */ f=NULL; if (outfile==NULL) { #ifdef HAVE_DAC_DEVICE /* if no outfile then write direct to DAC */ /* if no format specified then try 16 bit */ i=(afmt==AFMT_QUERY)?AFMT_S16_LE:afmt ; if ((fd=DACopen(fnm=dac,"w",&samplerate,&i,&stereo))<0) { if (afmt==AFMT_QUERY) { /* if no format specified try for 8 bit.. */ i=AFMT_U8; fd=DACopen(fnm,"w",&samplerate,&i,&stereo); } if (fd<0) exit(err_rpt(errno,fnm)); } if ((frag_size=getfragsize(fd))<0) exit(err_rpt(errno,"Problem getting DAC Buffer size.")); if (vflg) { printf("%s : DAC Opened for output\n",fnm); printf("%d bytes per DAC buffer.\n",frag_size); } if ((afmt!=AFMT_QUERY && i!=afmt) || stereo!=0) { if (i!=afmt) err_rpt(EINVAL,"Sound card doesn't support requested sample format."); if (stereo!=0) err_rpt(EINVAL,"Card doesn't do MONO - nah, don't believe it."); exit(EINVAL); } afmt=i; #else /* error if no outfile specified */ exit(help(err_rpt(EINVAL,"No output file specified, use -w or -o option."))); #endif } else { if (strcmp(outfile,"-")==0) { if (aflg) exit(err_rpt(EINVAL,"Cannot write append to stdout.")); f=stdout; fnm="stdout"; } else { if (aflg && wfmt) { exit(err_rpt(EINVAL,"Cannot write append to a WAVE file.")); } afmt=(afmt==AFMT_QUERY)?AFMT_S16_LE:afmt ; /* set 16 bit mode unless * some format is forced */ omode=(aflg)?"a":"w"; if ((f=fopen(fnm=outfile,"r"))!=NULL) { fclose(f); if ( (!aflg) && (!fflg) ) exit(err_rpt(EEXIST,fnm)); } if ((f=fopen(fnm,omode))==NULL) { exit(err_rpt(errno,fnm)); } frag_size=32768; if (vflg) { printf("%s samples to %s file %s\n", (*omode=='a')?"Appending":"Writing", (wfmt)?"WAVE":"RAW", fnm); printf("Buffer size is %d bytes.\n",frag_size); } fd=fileno(f); if (loopflg<0) loopflg=0; /* cannot loop forever if writing to a file */ if (wfmt && (fWAVwrhdr(f,0,samplerate,afmt,stereo)<0)) { exit(err_rpt(errno,"Writing WAVE file header.")); } } if (fWAVinit(0,samplerate,afmt,stereo)) { exit(err_rpt(errno,"Initialising sound file parameters.")); } } if (!(afmt==AFMT_S16_LE || afmt==AFMT_U8)) { exit(err_rpt(EINVAL, "Only unsigned 8 and signed 16 bit samples supported.")); } if (vflg) { if (vflg>1) fWAVdebug(stdout); printf("%d %s, %s, samples/sec\n",samplerate, (stereo)?"stereo":"mono", (afmt==AFMT_U8)?"unsigned 8 bit": ((afmt==AFMT_S16_LE)?"signed 16 bit, little endian": "Unknown audio format")); printf("Upto %d Frequencies can be played together.\n",channels); printf("%d loadable waveforms specified.\n",LWn); printf("Tone levels are %s.\n",(Abs_Level)?"ABSOLUTE":"RELATIVE"); } /* initialise base samples etc */ TWn=LWn; init_samples(f,fd,frag_size,samplerate,afmt,stereo,channels,&TWn); if (LWn && (st=do_loadable_waveforms(LWaa,LWn,TWn,vflg))) exit(st); do { for ( i=0; i %s\n",argv[i],getGenErrStr()); } } if (fi!=NULL) ftones(fi,infile); if (loopflg>0) loopflg--; } while (loopflg); if (outfile==NULL) { flush_samples(); close(fd); } else { if (wfmt && (fWAVwrhdr(f,getsamples(),samplerate,afmt,stereo)<0)) { err_rpt(errno,"Rewriting WAVE file header."); } fclose(f); } exit(0); } siggen-2.3.10/wavsubs.h0000600000175000017500000000447211011642302013347 0ustar jjfamily/* wavsubs.h * Functions for opening, closing, reading, writing WAV files - include file * Jim Jackson */ /* * Copyright (C) 1998-2008 Jim Jackson jj@franjam.org.uk * * This include file is part of free software; you can redistribute it * and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * See file COPYING for details. */ /* HISTORY * * 2 Dec 98 Started */ #ifndef __WAVSUBS_H #define __WAVSUBS_H #include #ifndef AFMT_S16_LE # define AFMT_S16_LE 16 #endif #ifndef AFMT_U8 # define AFMT_U8 8 #endif #ifndef STEREO # define STEREO 1 #endif #ifndef MONO # define MONO 0 #endif /* WavValues structure for holding information about a set of samples */ struct WavValues { int samples; /* number of samples */ int samplerate; /* samplerate at which data was sampled */ int stereo; /* stereo (1) or mono (0) data */ int afmt; /* format of samples unsigned 8 bit (8) or Signed 16 bit little endian (16) */ int Bps; /* Bytes per sec */ int Bypsam; /* Bytes per sample */ }; /* Functions definitions...... */ int isriff(FILE *f); int wavreadfmt(FILE *f,struct WavValues *W); int wavwritefmt(FILE *f,struct WavValues *W); int wavread(FILE *f,struct WavValues *W,unsigned char *buf,int N); int wavwrite(FILE *f,struct WavValues *W,unsigned char *buf,int N); int setendian(); /* Macros provided in wavsubs.h for struct WavValues ....... */ #define GetWavSamplerate(W) ((W)->samplerate) #define SetWavSamplerate(W,S) ((W)->samplerate = S) #define GetWavStereo(W) ((W)->stereo) #define SetWavStereo(W,S) ((W)->stereo = S) #define GetWavAFmt(W) ((W)->afmt) #define SetWavAFmt(W,F) ((W)->afmt = F) #define GetWavSamples(W) ((W)->samples) #define SetWavSamples(W,N) ((W)->samples = N) #define IsWavStereo(W) ((W)->stereo == STEREO) #define IsWavMono(W) ((W)->stereo == MONO) #define IsWav16bit(W) ((W)->afmt == AFMT_S16_LE) #define IsWav8bit(W) ((W)->afmt == AFMT_U8) #define NewWavValues() ((struct WavValues *)malloc(sizeof(struct WavValues))) extern int ISBIGENDIAN; struct WavValues *Winit(); #endif /* __WAVSUBS_H */ siggen-2.3.10/tt.c0000600000175000017500000000007407632727155012321 0ustar jjfamily #include main() { printf("%d\n",INT_MAX); } siggen-2.3.10/siggen.conf.50000600000175000017500000002057311011657024014001 0ustar jjfamily.TH siggen.conf 5 "07Feb99" "Release 2.3" "Linux System Manual" .SH NAME .I siggen.conf \- the siggen configuration files .SH SYNOPSIS .B siggen.conf .SH DESCRIPTION .PP As from siggen version 2.3 onwards a versatile configuration file scheme has been introduced. It allows parameters for the siggen programs to be specified either across the board, or specifically for particular programs. .PP Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. .PP All the programs are compiled with the names of the config files built in. The filenames are set in the config.h header file and can be changed. The LOCAL and GLOBAL config files are specified by the settings of: .IP LOCAL #define DEF_CONF_FILENAME ".siggen.conf" .IP GLOBAL #define DEF_GLOBAL_CONF_FILE "/etc/siggen.conf" .PP And can be set to any file name or to NULL to disable the file. The HOME config filename is created using the $HOME environment variable and the DEF_CONF_FILENAME together, i.e. using the above, the HOME config file for a user whose home directory is at /home/jj, would be .IP HOME /home/jj/.siggen.conf .PP The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. .PP The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. .PP If no configuration files exist, the programs themselves provide builtin default values (see config.h etc), and most of these values can be set by appropriate command line switches and flags. .SH CONFIGURATION\ VALUES .PP A configuration value has a name and a value, and values for all programs are set by simply entering a line in the appropriate config file where the first word is the name, followed by arbitrary spaces/tabs, followed by the value. The value is all the rest of that line. e.g. to set the global default samplerate of 44100 samples per sec, the following line would be entered in the GLOBAL config file: .IP SAMPLERATE\ \ \ \ \ 44100 .PP Config value names are case insensitive. .PP A config value can be set for a specific program, by prefixing the config value name with the program name and a ':'. e.g. to specify a samplerate of only 8000 samples per sec for the tones program enter .IP TONES:SAMPLERATE\ \ \ \ 8000 .PP in the relevant config file. If both lines above were in the config file, all programs except tones would use a samplerate of 44100, and tones would use 8000. .PP You do not have to specify all configuration values in the config files. If a particular value is missing, the programs will simply use their builtin defaults (see config.h etc). .PP Configuration values set by command line switches or flags take precedence over values in any of the config files. .I .IP Beware the programs do not have their 'name' built-in, but use the name they were invoked by. So if you change the name of a program, remember to change the config file entries. However this does means that by using links to a program, it can be made to pick up a different set of configuration values, depending on the name it is invoked by. .SH EXAMPLE\ CONFIGURATION\ FILE .PP A sample config file is provided in ".siggen.conf" in the distribution. This may also be at /etc/siggen.conf . Any line whose first non-whitespace character is a '#', is a comment line and is ignored. .SH WHAT\ CONFIGURATION\ VALUES\ ARE\ THERE? .PP Not all of the siggen programs use all the values described here. See the relevant man page for which values are used by which programs. .I .IP CHANNELS In all programs except tones and fsynth, channels specifies the number of output channels to use, i.e. 1 for Mono and 2 for Stereo. .IP For tones, channels specifies the number of 'voices' on which tones can generate different waveforms before mixing them into the one output channel. .IP For fsynth, channels specifies the numbers of seperately configurable oscillators used to mix the single output channel. .I .IP DACFILE The Digital to Analogue Converter (or PCM or DSP) device on which to output the generated samples. This must be a real OSS PCM device, otherwise the ioctls used will fail. .I .IP FRAGMENTS The number of Audio Buffer fragments to configure in the driver. The interactive programs respond to changes made to parameters from the keyboard immediately, but data will be buffered in the driver in the buffer fragments. If the amount of data buffered is too much then there will very noticable delays before the output sound is altered. Against that, insufficient buffering may mean that there is not enough data buffered for output to cover the time when other processes are being run by the scheduler. The programs set the buffer size to the nearest power of 2 to give aprox. 100millisecs of sound. Hence if FRAGMENTS is set to 3, there will be aprox. 0.3 secs worth of sound buffered for output. On a lightly loaded fast machine this, or 2, should be sufficient. To cover periods of heavy load or on a less powerful machine use 4 or 5. But remember the interactive programs will appear sluggish in responding to the keyboard. .I .IP SAMPLERATE The number of samples per second to use. If output is to the DAC then the DAC device is set to output samples at this rate. .br .I BEWARE: not all cards can support all samplerates. SoundBlasters are fairly flexible in this respect. Other cheaper cards are not. Indeed some cards can only handle a very restricted set of related samplerates e.g. 11025, 22050, 44100 & 8000, 16000, 32000, 48000. When writing to DACFILE all programs will attempt to set the samplerate given, but use the actual samplerate the device used. Use the verbose command line flag to check actual samplerates used. .PP Some common samplerates used are: .I .IP \ \ \ \ 8000 is the samplerate used in the phone system with 8 bit samples, and is adequate for voice range frequencies. .I .IP \ \ \ \ 44100 is the samplerate used in audio CDs .I .IP \ \ \ \ 48000 is the samplerate used in DAT systems, I think, and for much professional kit. .I .IP \ \ \ \ 32000 is also used, but I forget where, minidisc?. .IP In general, the higher the samplerate the larger the memory and processing requirement, but the higher the frequency range and the more accurate the signals generated. .I .IP SAMPLESIZE Number of bits per sample. Only two values are allowed currently, 8 or 16. .I .IP \ \ \ \ 8 bit samples are unsigned, with decimal value 128 being the \'zero\' level. .I .IP \ \ \ \ 16 bit samples are signed little endian values, i.e. the least significant byte comes before the most significant byte either in a file, or in the byte stream to an output device. .IP If samplesize if left completely unspecified, then all programs will attempt to do 16 bit samples to DACFILE, and if that isn't possible will do 8 bit samples. Or if writing to a file, 16 bit samples will be written. .I .IP VERBOSE sets verbosity level. .I .IP \ \ \ \ 0 is quiet .I .IP \ \ \ \ 1 is be a bit verbose (equiv. to -v switch) .I .IP \ \ \ \ 2 is be very verbose (equiv. to -vv switch) .I .IP VI_KEYS if set to a non-zero value, then the VI cursor moving keys "HJKL" are enabled. .SH SEE ALSO .IP sgen(1),\ swgen(1) .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/swgen.c0000600000175000017500000003742211011656617013012 0ustar jjfamily/* swgen.c * sweep generator and more. * Jim Jackson Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* History................... * * 09Mar03 Bug fixed in calculating playsamples for long periods * 16Feb03 Add -A option for digital gain - as per sgen * 3Jun99 Some tidying up of WAV file writing * 1Sep98 added configuration file(s) support * 18Jun98 added the x10 feature where frequencies are specified * as integers 10 times too big, so that freqs with a resolution * of 0.1 Hz can be generated. * 18Jun98 Made compilable on machines without soundcard support and * under sunos (bigendian machine) * 04Aug97 Add -t time playing option. * 24Mar97 Added a specialist stereo option. It outputs the FM waveform * on one channel and the sweep on the second channel. * The FM signal can be used to trigger the scope - or even * drive the scope timebase used to monitor the swept freq. * in freq response measurements. * 17Mar97 initial version based on tones.c as a skeleton. * generates a 1Hz wave for the basic waveform and a standard * wave of correct frequency for the * FM waveform. For unmodulated freq F, sample the basic buffer * every F samples, wrapping approp. from end to start. * To FM modulate it use the sample values from the FM waveform * to determine the (now variable) increment F. * The default is to generate a sawtooth ramp wave for the FM * and a sine wave as the basic, swept, waveform. * */ #include #include #include #include #include #include #include #include #include #include #include "fmtheaders.h" #include "config.h" #define VERSTR "%s Ver. %s Digital Sweep Generator\n" #define EFAIL -1 #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) int aflg,fflg,vflg,dflg,wfmt; unsigned int Gain; /* Amplification factor */ unsigned int stereo; /* stereo or mono mode */ unsigned int freqX; /* multiplication factor for freq. spec. */ /* actual freq. is given freq / freqX */ unsigned int samplerate; /* Samples/sec */ unsigned int afmt; /* format for DAC */ unsigned int abuf_size; /* audio buffer size */ int frag_size; /* size of a DAC buffer */ char *waveform; /* Waveform to generate for tones */ unsigned char *swbuf; /* sample buff for swept waveform */ unsigned int Frq,Frqmin,Frqmax; /* Mid point freq of sweep and min and max */ char *FMwave; /* modulation waveform */ unsigned char *FMbuf; /* sample buff for sweep waveform */ unsigned char *FM8buf; unsigned int FMfrq; /* frequency of modulation waveform */ unsigned int tbuf_size; /* tone buffer size */ unsigned int plbuf_size; /* play buffer size */ unsigned char *silbuf; /* silence buffer */ unsigned char *tbuf,*plbuf; /* tbuf holds the sweep samples for 1 sec * plbuf is tbuf if in mono mode * else is the interleaved 2 channels */ long playtime,playsamples; /* number of millisecs/samples to play 0 means play for ever */ char *sys,*outfile; char dac[130]; char *configfile; unsigned char *maketone(); help(e) int e; { char **aa; fprintf(stderr,VERSTR,sys,VERSION); fputs("\nGenerates a swept waveform. Both the swept waveform and the sweeping\n",stderr); fputs("waveform can be:",stderr); for ( aa=(char **)getWavNames(); *aa; aa++ ) fprintf(stderr," %s",*aa); fputs("\n",stderr); fputs("The sweep range can be specified as a min. freq and max. freq, or as\n",stderr); fputs("centre freq and percentage variation. All frequencies are Hertz\n",stderr); fputs("and are integers (but see the -x10 and -x100 options).\n\n",stderr); fputs("Usage: swgen [options/flags] [sweepwaveform] sweepfreq\n",stderr); fputs(" [sweptwaveform] minfreq maxfreq | centrefreq percent%\n",stderr); fputs("Defaults: sweeping waveform is sawtooth, swept waveform is sine,\n",stderr); #ifdef HAVE_DAC_DEVICE fprintf(stderr," output to %s, %d 16 bit mono samples/sec, if possible,\n", DAC_FILE,SAMPLERATE); fputs(" else 8 bit samples.\n",stderr); #else fprintf(stderr," %d 16 bit mono samples/sec. Must be used with -o or -w option.\n", SAMPLERATE); #endif fputs("flags: -f,-a force overwrite/append of/to file\n",stderr); fputs(" -o file write digital samples to file ('-' is stdout)\n",stderr); fputs(" -w file as '-o' but written as a wave file\n",stderr); fputs(" -s samples generate with samplerate of samples/sec\n",stderr); fputs(" -v be verbose.\n",stderr); fputs(" -8/-16 or -b 8|16 force 8 bit or 16 bit mode.\n",stderr); fputs(" -2 special stereo mode, swept waveform to one channel\n",stderr); fputs(" sweeping waveform to other channel.\n",stderr); fputs(" -A n scale samples by n/100, def. n is 100\n",stderr); fputs(" -t N|Nm N secs or Nm millisecs of samples\n",stderr); fputs(" -x10|-x100 scale freqs down by factor of 10/100\n",stderr); fputs(" allows freqs to 0.1/0.01 of a hertz.\n",stderr); return(e); } /* main * */ main(argc,argv) int argc; char **argv; { unsigned int i,j,k,l,m,n,N; FILE *f; char *p,*wf,*fnm,fname[130],*omode; int fd,st; unsigned int t; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; waveform="sine"; FMwave="sawtooth"; outfile=NULL; samplerate=0; afmt=AFMT_QUERY; stereo=-1; Gain=100; playtime=playsamples=dflg=vflg=aflg=fflg=0; freqX=1; while (argc && **argv=='-') { /* all flags and options must come */ n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (chkword(1,"samplerate")) { if (argc && isdigit(**argv)) { samplerate=atoi(*argv++); argc--; } } else if (chkword(4,"x100")) { freqX=100; } else if (chkword(3,"x10")) { freqX=10; } else if (chkword(1,"output")) { /* specify output file */ if (argc) { outfile=*argv++; argc--; } /* output file name */ } else if (chkword(1,"wave")) { /* e.g. write WAVE format file */ if (argc) { outfile=*argv++; argc--; wfmt=1; } /* output file name */ } else if (chkword(1,"A")) { if (argc && isdigit(**argv)) { Gain=atoi(*argv++); argc--; } } else if (chkword(2,"16")) { afmt=AFMT_S16_LE; } else if (chkword(1,"bits")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i==8) afmt=AFMT_U8; else if (i==16) afmt=AFMT_S16_LE; else exit(err_rpt(EINVAL,"must be '-b 8' or '-b 16'.")); } else if (chkword(1,"time")) { i=0; if (argc) { i=strtol(*argv++,&p,10); argc--; if (*p=='s' || *p==0) i*=1000; /* time specified in secs - *1000 for ms */ else if (*p!='m') exit(err_rpt(EINVAL,"Invalid time specification.")); } playtime=i; } else if (chkword(1,"config")) { if (argc && **argv != '-') { configfile=*argv++; argc--; } } else { /* check for single char. flags */ for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='8') afmt=AFMT_U8; else if (*p=='1') stereo=0; else if (*p=='2') stereo=1; else if (*p=='a') aflg=1; else if (*p=='f') fflg=1; else if (*p=='d') dflg=1; else if (*p=='v') vflg++; else { *fname='-'; *(fname+1)=*p; *(fname+2)=0; exit(help(err_rpt(EINVAL,fname))); } } } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (samplerate==0) { samplerate=atoi(get_conf_value(sys,"samplerate",QSAMPLERATE)); } if (stereo==-1) { stereo=atoi(get_conf_value(sys,"channels","1")); if (stereo) stereo--; } if (afmt==AFMT_QUERY) { afmt=atoi(get_conf_value(sys,"samplesize",QAFMT_QUERY)); } strncpy(dac,get_conf_value(sys,"dacfile",DAC_FILE),sizeof(dac)-1); /* check sweep params ........ */ if (argc && !isdigit(**argv)) { /* if first param is not numeric */ FMwave=*argv++; argc--; /* must be the modulating waveform type */ } if (argc==0 || !isdigit(**argv)) { /* next param must be sweep frequency */ exit(help(err_rpt(EINVAL,"Invalid sweep frequency."))); } FMfrq=atoi(*argv++); argc--; if (argc && !isdigit(**argv)) { /* if next param is not numeric */ waveform=*argv++; argc--; /* it must be swept waveform type */ } if (argc!=2) { /* should be exactly 2 params left */ exit(help(err_rpt(EINVAL,"Invalid number of parameters."))); } Frq=atoi(*argv++); argc--; n=strtol(*argv,&p,10); if (*p=='%') { if (n>100) exit(help(err_rpt(EINVAL,"Percent variation must be <= 100%"))); Frqmin=Frq-((Frq*n+50)/100); Frqmax=Frq+((Frq*n+50)/100); } else { Frqmin=Frq; Frqmax=n; Frq=(Frqmin+Frqmax+1)/2; if (Frqmin>Frqmax) { n=Frqmin; Frqmin=Frqmax; Frqmax=n; } } if (Frqmax==0 || Frqmax>=((freqX*samplerate)/2)) { exit(help(err_rpt(EINVAL,"Specified Max freq. is either 0 or greater than half the samplerate"))); } /* open the right device or output file............ */ if (vflg) printf(VERSTR,sys,VERSION); if (outfile==NULL) { #ifdef HAVE_DAC_DEVICE /* if no outfile then write direct to DAC */ /* if no format specified then try 16 bit */ i=(afmt==AFMT_QUERY)?AFMT_S16_LE:afmt ; n=stereo; if ((fd=DACopen(fnm=dac,"w",&samplerate,&i,&n))<0) { if (afmt==AFMT_QUERY) { /* if no format specified try for 8 bit.. */ i=AFMT_U8; fd=DACopen(fnm,"w",&samplerate,&i,&n); } if (fd<0) exit(err_rpt(errno,fnm)); } if ((frag_size=getfragsize(fd))<0) exit(err_rpt(errno,"Problem getting DAC Buffer size.")); afmt=i; if (vflg) { printf("%s : DAC Opened for output\n",fnm); printf("%d %s, %s, samples/sec\n",samplerate, (stereo)?"stereo":"mono", (i==AFMT_U8)?"unsigned 8 bit": ((i==AFMT_S16_LE)?"signed 16 bit, little endian": "Unknown audio format")); printf("%d bytes per DAC buffer.\n",frag_size); } if (i!=afmt || stereo!=n) { exit(err_rpt(EINVAL,"Sound card doesn't support requested format.")); } #else /* error if no outfile specified */ exit(help(err_rpt(EINVAL,"No output file specified, use -w or -o option."))); #endif } else { if (aflg && wfmt) { exit(err_rpt(EINVAL,"Cannot write append to a WAVE file.")); } afmt=(afmt==AFMT_QUERY)?AFMT_S16_LE:afmt ; /* set 16 bit mode unless * some format is forced */ omode=(aflg)?"a":"w"; if ((f=fopen(fnm=outfile,"r"))!=NULL) { fclose(f); if ( (!aflg) && (!fflg) ) exit(err_rpt(EEXIST,fnm)); } if ((f=fopen(fnm,omode))==NULL) { exit(err_rpt(errno,fnm)); } if (vflg) { printf("%s : Opened %s.\n",fnm, (*omode=='a')?"in append mode":"clean for writing"); } fd=fileno(f); if (playtime==0) playtime=DEF_PLAYTIME; } /* calc number of samples to play */ if (playtime) { if ((playsamples=mstosamples(playtime,samplerate))==0) exit(err_rpt(EINVAL,"Arithmetic overflow when calculating number of samples.")); } tbuf_size=samplerate*freqX; /* buf sizes if 8 bit samples */ if (afmt==AFMT_S16_LE) tbuf_size<<=1; /* double size if 16 bit */ else if (afmt!=AFMT_U8) { exit(err_rpt(EINVAL,"Only unsigned 8 and signed 16 bit, supported.")); } if (vflg) { printf("%s bit samples being generated.\n", (afmt==AFMT_S16_LE)?"16":"8"); printf("%d byte buffers being allocated.\n",tbuf_size); if (freqX>1) printf("All frequency values to be divided down by %d\n",freqX); printf("%s wave being swept from %d Hz to %d Hz by\n", waveform,Frqmin,Frqmax); printf("a sweeping %s wave at %d Hz.\n",FMwave,FMfrq); if (playtime) { printf("Playing for %d.%03d millisecs, %d samples.\n", playtime/1000,playtime%1000,playsamples); } printf("Samples scaled by a factor of %d/100.\n",Gain); } if ((swbuf=maketone(waveform,1,samplerate*freqX,Gain,afmt))==NULL || (FMbuf=maketone(FMwave,FMfrq,samplerate*freqX,100,AFMT_S16_LE))==NULL) { exit(err_rpt(ENOMEM,"Out of Memory or Cannot Generate Waveforms.")); } if ((tbuf=malloc(tbuf_size))==NULL || mksweep(tbuf,tbuf_size,(short int *)FMbuf,swbuf,Frqmin,Frqmax,samplerate*freqX,afmt)==0) { exit(err_rpt(EINVAL,"Out of Memory or Problem generating Swept waveform.")); } if (stereo) { plbuf_size=tbuf_size< #include #include #include #include #include #include #include #include #include #include /* DACopen(device,mode,&samplerate,&fmt,&stereo) * opens device for mode (r/w) at samplerate samples/sec in 8/16 bit fmt * and in stereo. Sets these params to best match possible. * * getfragsize(fd) * get fragment size of a DSP buffer * * getfreeobufs(fd) * return number of free output fragment buffers free at moment * * getfullibufs(fd) * return number of full input fragment buffers full at moment * * setfragsize(fd,N,bfps,S,afmt,stereo) * set number of buffers to N and size such that we get aprox bfps buffers * played per second. S samples per sec of mono/stereo, 8/16 bit samples. * * is16bit(fd) * returns true if file fd is a 16 sound device * * isstereo(fd) * returns true if file fd is a stereo sound device (To Be Done) */ /* is16bit(fd) return true if fd is a dsp device supporting 16 bit * sampling. Return false if not. */ is16bit(fd) int fd; { int fmts; if (ioctl(fd, SNDCTL_DSP_GETFMTS , &fmts) < 0) { return(0); } return(fmts&AFMT_S16_LE); } /* getfragsize(fd) return fragsize of DSP buufer for fd * or return -1 on error. */ getfragsize(fd) int fd; { int n; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &n)<0) return(-1); return(n); } /* getfreeobufs(fd) return number of empty output fragment buffers * available or return -1 on error. */ getfreeobufs(fd) int fd; { int n; audio_buf_info osp; if (ioctl(fd,SNDCTL_DSP_GETOSPACE, &osp)<0) return(-1); return(osp.fragments); } /* getfullibufs(fd) return number of full input fragment buffers * available or return -1 on error. */ getfullibufs(fd) int fd; { int n; count_info isp; if (ioctl(fd,SNDCTL_DSP_GETIPTR, &isp)<0) return(-1); return(isp.bytes); } /* printibufs(fd) print input audio_buf_info * return -1 on error. */ printibufs(fd) int fd; { int n; count_info isp; if (ioctl(fd,SNDCTL_DSP_GETIPTR, &isp)<0) return(-1); printf("Count Info: bytes=%d, blocks=%d, ptr=%0Xx\n", isp.bytes, isp.blocks, isp.ptr); return(0); } /* setfragsize(fd,N,bfps,S,afmt,stereo) * calculate buffer size to ensure aproximately * bfps buffers per second, then set N buffs of this size * afmt is 8 or 16 bit samples, stereo is true if 2 chans * return -1 if error - see errno, else return fragsize * set. */ setfragsize(fd,N,bfps,S,afmt,stereo) int fd,N,bfps,S,afmt,stereo; { int fr,n; if (N<1) { errno=EINVAL; return(-1); } n=S/bfps; /* n is samplerate / buffers/sec */ for (fr=5; (2<= 0) { /* params must be set in this order */ if ((*fmt==AFMT_QUERY) && is16bit(fd)) *fmt=AFMT_S16_LE; if (ioctl(fd, SNDCTL_DSP_SETFMT, fmt)>=0) { if (*stereo==-1) { *stereo=1; if (ioctl(fd, SNDCTL_DSP_STEREO, stereo)<0) *stereo=0; } if (ioctl(fd, SNDCTL_DSP_STEREO, stereo)>=0) { if (ioctl(fd, SNDCTL_DSP_SPEED, samples)>=0) { return(fd); } } } } return(-1); } siggen-2.3.10/sweepgen.10000644000175000017500000001646211011657052013425 0ustar jjfamily.TH sweepgen 1 "20 Feb 1998" "Release 2" "Linux System Manual" .SH NAME .I sweepgen \- an Ncurses based sweep generator program .SH SYNOPSIS .IP sweepgen\ [options] .SH DESCRIPTION .I sweepgen is a simple sweep signal generator program, with an Ncurses based user interface, that can digitally generate waveforms on the LINUX .B /dev/dsp device. 8 or 16 bit samples can be generated depending on the hardware. .PP .I sweepgen in .B MONO mode outputs the generated swept waveform. In .B STEREO mode the swept waveform is output on one channel, and the sweeping waveform is output on the second channel. .PP The sweeping frequency is by default specified as an integer number of Hertz. Fractional Hertz frequencies, specifiable to 0.1Hz or 0.01Hz resolution, are supported by use of the .I -res command line option, or the .I resolution parameter in the configuration file(s). However .I be\ warned at 0.1Hz resolution the basic waveform sample buffers generated are each 10 times (and at 0.01Hz resolution 100 times) as big as the samplerate. It typically requires 5.5Mbytes of memory to run at 0.1Hz resolution, 16bit 32000 samples/sec. and 55Mbytes of memory to run at 0.01Hz resolution. Because of the large buffer sizes, the initial waveform calculation time can also be lengthy. Remember also that the waveforms are re-calculated whenever the playing parameters, 8/16bit, mono/stereo, samplerate are changed. .PP The swept waveform frequencies are specified either as a lower and upper frequency, or as a centre frequency with a frequency variation. .IP 1000\ 500 would signify a range of 1000-500 Hz to 1000+500 Hz, i.e. 500 to 1500 Hz .PP Of course, only frequencies less than half the samplerate (number of samples/sec) can be generated. Although this is not checked. .PP The waveforms that can be used as either the sweeping or swept signals are: .IP sine A standard sine wave .IP square a standard square wave with a 50% mark space ratio .IP triangle a linear rise from 0 to peak, thru' 0 to negative peak, and back to 0 .IP sawtooth a ramp waveform with 'infinitely' fast flyback (:-) An ideal oscilloscope timebase signal. .IP noise This is weak. All it consists of is one second of pseudo-randomly generated samples, played repeatedly. I'd love to do proper white/pink noise, but I don't know enough, and I don't think the structure of the program is conducive to accurate noise generation. .IP pulse A square waveform where the mark/space ratio (as a percentage) is 10% (mark/space ratio of 1:9). .PP A lot of thought has gone into the algorithms for generating the waveforms. I believe the sin/cos wave to be very pure (modulo your sound card :-), but I don't have access to a THD meter to measure it. .PP At 1Hz resolution, .I sweepgen generates one seconds worth of 1 Hz samples at the specified samplerate, for each waveform, and generates sweeping frequency F by circularly sampling every Fth sample. These samples are scaled to fit the swept frequency range and are used to sample the swept waveform to generate the swept signal. Each buffer fragment is generated for the parameter(s) set at that moment. By default, buffer fragment sizes are set so that aprox. 10 fragments/sec are generated. Changing a generation parameter, e.g. waveform, frequency, will impact the next buffer fragment generated, and hence changes appear to be almost immediate. .PP If your sounds periodically 'breaks' up with clicks or breaks, it is usually a sign that siggen is not being scheduled sufficiently often. Either up the priority (see .I nice et al.), kill off other processes, get a faster processor, or increase the number of audio buffer fragments that siggen uses. This last will make siggen respond more sluggishly to changes in generation parameters. .I syslogd and .I crond are two processes that I've found useful to kill off - YMMV. .IP Defaults output to /dev/dsp, 22050 samples/sec, stereo if stereo card else mono, 16 bit samples if possible, else 8 bit. .SH CONFIGURATION\ FILES .PP Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. .PP All the siggen suite of programs are compiled with the names of the config files built in. By default the configuration files are: .IP ./.siggen.conf is the LOCAL config file. .IP $HOME/.siggen.conf is the HOME config file. .IP /etc/siggen.conf is the GLOBAL config file. .IP siggen\ -h will indicate which config files will be searched for. .PP The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. .PP The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. .PP If no configuration files exist, the program provides builtin default values, and most of these values can be set by appropriate command line switches and flags. .PP See siggen.conf(5) for details of the configuration files. .PP .I sweepgen looks for configuration values BUFFERSPERSEC, CHANNELS, DACFILE, FRAGMENTS, RESOLUTION, SAMPLERATE, SAMPLESIZE, VERBOSE, VI_KEYS. .IP BUFFERSPERSEC The aprox. number of sound buffer fragments to play every second (Sound buffersize is always a power of 2). .IP CHANNELS sets the number of channels, mono or stereo. .IP DACFILE allows the name of the DAC/DSP/PCM device to be changed from /dev/dsp .IP FRAGMENTS The number of Audio Buffers to configure in the driver. .IP RESOLUTION The minimum change possible to the frequency setting. Only 3 values allowed: 1Hz , 0.1Hz or 0.01Hz .IP SAMPLERATE sets the number of samples/sec for the DAC device .IP SAMPLESIZE sets whether 8 or 16 bit samples to be generated .IP VERBOSE sets whether or not to run in verbose mode. .IP VI_KEYS if set then the VI cursor moving keys "HJKL" are enabled .SH OPTIONS .IP -h display usage and help info .IP -v be verbose .IP -s\ samples generate with samplerate of samples/sec .IP -8|-16\ or\ -b\ 8|16 force 8 bit or 16 bit mode. .IP -1|-2 mono or stereo mode .IP -res\ n set resolution of frequency generation. Valid values are: 1Hz, 0.l1Hz or 0.01Hz .SH EXAMPLES .SH .SH FILES .SH .SH SEE ALSO swgen, sgen, siggen, tones .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/.siggen.conf0000600000175000017500000000316611011657545013723 0ustar jjfamily# default DAC digital analogue converter device name dacfile /dev/dsp # default mixer device file.... mixerfile /dev/mixer # default samplerate samplerate 22050 # for siggen & sweepgen set a samplerate of ...... siggen:samplerate 32000 sweepgen:samplerate 32000 # default number of channels is 1. i.e. mono output channels 1 # but for siggen, sweepgen default is stereo..... siggen:channels 2 sweepgen:channels 2 # and for tones default channels is 8 # No not quadraphonic, but the number of different freqs that be mixed # and played at once. tones:channels 8 # and for fsynth default channels is 13 # The number of harmonics that can mixed to make the waveform fsynth:channels 13 # default samplesize is usually to try for 16 bit and if that fails # to try 8 bits. If anything is actually specified either on command # line or in config file then that is attempted only. #samplesize 16 # default number of audio buffer fragments for interactive programs # compromise between sufficient buffering for playahead to cover # time when other programs are scheduled, and time it takes for # changes in generation parameters to feed thro' to being heard. # Too low a value and sound will break up. # Too high a value and programs will feel very unresponsive to changes fragments 4 # default number of buffers per second required. This is used to calculate # the buffer fragment size. It is always to nearest power of 2. bufferspersec 15 # default gain is in dB gain dB # number of loadable waveforms allowed........ #loadable_waveforms 10 # default verbosity is 0 verbose 0 # vi_keys by default they are turned off vi_keys 0 fsynth:vi_keys 0 siggen-2.3.10/tones.eg/0002700000175000017500000000000010021450602013217 5ustar jjfamilysiggen-2.3.10/tones.eg/randnote.c0000600000175000017500000000277106474557403015234 0ustar jjfamily/* randnote.c * generate random a random walk for musical notes and duration * to feed to tones program to play random notes. * * Usage: randnote startnote [millisecs [iterations]] * * default millisecs is 250, default iterations is 1000 */ #include char NT[6]; char Nl[]="CDEFGABC"; main(argc,argv) int argc; char **argv; { int i,f,Id,d,N,x; argv++; argc--; if (argc<1 || argc>3) { printf("Usage: randnote start_note [duration [num_notes]]\n"); printf("\n start_note is letter[#]digit , where letter specifies the\n"); printf(" note, '#' is used to sharpen the note, and digit specifies the\n"); printf(" octave. Middle C is 'C3'.\n"); printf(" duration is in millisecs (def. 250), def num_notes is 1000\n"); exit(1); } Id=250; N=1000; strncpy(NT,*argv,5); argv++; argc--; NT[5]=0; if (islower(NT[0])) NT[0]=toupper(NT[0]); if (strlen(NT)!=2 || NT[0]<'A' || NT[0]>'G' || !isdigit(NT[1])) { printf("Illegal start note. Use A-G followed by a single digit.\n"); exit(1); } f=((NT[0]-'C'+7)%7)+(NT[1]-'0')*7; if (argc) { Id=atoi(*argv++); argc--; if (argc) { N=atoi(*argv); } } srandom(time(NULL)%(Id+f)); d=Id; for (i=0; i69) f=70-f; x=(random()%5)-2; if (x>0) d=(Id<>(-x)); if (x==0) d=Id; } } siggen-2.3.10/tones.eg/ramp.sh0000700000175000017500000000061207460541003014523 0ustar jjfamily#!/bin/sh # demo using ramp # tones=../tones echo "executing: ./ramp 300 800 20 10 | $tones -i - sq 20" ./ramp 300 800 20 10 | $tones -i - sq 20 echo "executing: (./ramp 300 800 5 1 ; ./ramp 800 300 5 1) | $tones -i - sin 20" (./ramp 300 800 5 1 ; ./ramp 800 300 5 1) | $tones -i - sin 20 echo "executing: ./ramp 200 1000 5 4 | $tones -i - sin 10" ./ramp 200 1000 5 4 | $tones -i - sin 10 siggen-2.3.10/tones.eg/samples/0002755000175000017500000000000010021450603014676 5ustar jjfamilysiggen-2.3.10/tones.eg/samples/bassoon.tones0000644000175000017500000000011107340012112017402 0ustar jjfamily# build a bassoon 'f' like tone...... #sin :1000 1@-3.8,2@-3,3@-14,4@-13 siggen-2.3.10/tones.eg/samples/bassoonp.tones0000644000175000017500000000011307340012126017571 0ustar jjfamily# build a bassoon 'p' like tone...... #sin :1000 1@-0.8,2@-8.5,3@-20,4@-20 siggen-2.3.10/tones.eg/samples/organ.tones0000644000175000017500000000010307340012146017054 0ustar jjfamily#sin :1000 1@0,2@-10,4@-20,6@-30,8@-40,10@-50,12@-60,14@-70,16@-80 siggen-2.3.10/tones.eg/samples/violin.tones0000644000175000017500000000017007340012153017250 0ustar jjfamily#sin :1000 1@-30,2@-5.9,3@-3.45,4@-10.6,5@-10.7,6@-13.5,7@-30,8@-13.2,9@-30,11@-30,13@-27,15@-30,17@-19.6,18@-30,19@-27 siggen-2.3.10/tones.eg/samples/horn.tones0000644000175000017500000000011707340012137016721 0ustar jjfamily#sin :1000 #1@-1.8,2@-5.4,3@-14,4@-20 1@-5.9,2@-5.1,3@-5.9,4@-13,5@-10.5,6@-17 siggen-2.3.10/tones.eg/samples/flute.tones0000644000175000017500000000010107340012132017056 0ustar jjfamily#sin :1000 1@0,2@0,4@-20,6@-30,8@-40,10@-50,12@-60,14@-70,16@-80 siggen-2.3.10/tones.eg/samples/Makefile0000600000175000017500000000055107340015024016331 0ustar jjfamily# # Makefile for jj's siggen tones.eg/samples files ..... SHELL = /bin/sh # Edit SAMPLES to make the 1Hz + harmonic mixes to simulate different # instrument tones. SAMPLES = flute.wav organ.wav bassoon.wav bassoonp.wav violin.wav horn.wav att.wav # all: $(SAMPLES) %.wav: %.tones ../../tones -v -i $< -ch 20 -f -w $@ sin clean: rm -rf $(SAMPLES) *~ siggen-2.3.10/tones.eg/samples/att.tones0000644000175000017500000000043307340012103016535 0ustar jjfamily#sin :1000 #1,3@-6,5@-12,7@-18,9@-24,11@-30,13@-36,15@-42,17@-48,19@-54 #1,2@-3,3@-6,4@-9,5@-12,6@-15,7@-18,8@-21,9@-24,10@-27,11@-30,12@-33,13@-36,14@-39,15@-42,16@-45,17@-48,18@-51,19@-54,20@-57 1,2@-3,3@-6,5@-9,7@-12,11@-15,13@-18,17@-21,19@-24,23@-27,29@-30,31@-33,37@-36,41@-39 siggen-2.3.10/tones.eg/tune.sh0000700000175000017500000000060507075611317014551 0ustar jjfamily#!/bin/sh # demo using ramp # tones="../tones -load samples/flute.wav -load samples/organ.wav" f1=hole_bucket.notes f2=clementine.notes echo "there's a hole in my bucket - pure sine tones....." $tones -i $f1 sin echo "there's a hole in my bucket - using tone with harmonics....." $tones -i $f1 flute echo " " sleep 1 echo and now one with harmony...... $tones -i $f2 flute,sin,tri,sin siggen-2.3.10/tones.eg/shepard-risset-falling.tones0000644000175000017500000002476207076065233020705 0ustar jjfamilyecho Falling Shepard-Risset scale.... echo midfreq=500.000Hz number of partials is 7 echo density=1.200 number of frequency shifts=20 echo Freq range is 264.141Hz - 946.465Hz a bandwidth of 682.324Hz 938@-39.43,314@-29.14,377@-17.71,452@-6.29,543@-5.14,651@-16.57,782@-28.00 929@-38.86,311@-29.71,373@-18.29,448@-6.86,538@-4.57,645@-16.00,774@-27.43 921@-38.29,308@-30.29,370@-18.86,444@-7.43,533@-4.00,640@-15.43,767@-26.86 913@-37.71,306@-30.86,367@-19.43,440@-8.00,528@-3.43,634@-14.86,760@-26.29 904@-37.14,303@-31.43,363@-20.00,436@-8.57,523@-2.86,628@-14.29,754@-25.71 896@-36.57,300@-32.00,360@-20.57,432@-9.14,519@-2.29,622@-13.71,747@-25.14 888@-36.00,297@-32.57,357@-21.14,428@-9.71,514@-1.71,617@-13.14,740@-24.57 880@-35.43,295@-33.14,354@-21.71,424@-10.29,509@-1.14,611@-12.57,733@-24.00 872@-34.86,292@-33.71,350@-22.29,420@-10.86,505@-0.57,605@-12.00,727@-23.43 864@-34.29,289@-34.29,347@-22.86,417@-11.43,500@-0.00,600@-11.43,720@-22.86 856@-33.71,287@-34.86,344@-23.43,413@-12.00,495@-0.57,595@-10.86,713@-22.29 848@-33.14,284@-35.43,341@-24.00,409@-12.57,491@-1.14,589@-10.29,707@-21.71 841@-32.57,282@-36.00,338@-24.57,405@-13.14,487@-1.71,584@-9.71,701@-21.14 833@-32.00,279@-36.57,335@-25.14,402@-13.71,482@-2.29,579@-9.14,694@-20.57 826@-31.43,276@-37.14,332@-25.71,398@-14.29,478@-2.86,573@-8.57,688@-20.00 818@-30.86,274@-37.71,329@-26.29,394@-14.86,473@-3.43,568@-8.00,682@-19.43 811@-30.29,271@-38.29,326@-26.86,391@-15.43,469@-4.00,563@-7.43,675@-18.86 803@-29.71,269@-38.86,323@-27.43,387@-16.00,465@-4.57,558@-6.86,669@-18.29 796@-29.14,267@-39.43,320@-28.00,384@-16.57,461@-5.14,553@-6.29,663@-17.71 789@-28.57,264@-40.00,317@-28.57,380@-17.14,456@-5.71,548@-5.71,657@-17.14 782@-28.00,938@-39.43,314@-29.14,377@-17.71,452@-6.29,543@-5.14,651@-16.57 774@-27.43,929@-38.86,311@-29.71,373@-18.29,448@-6.86,538@-4.57,645@-16.00 767@-26.86,921@-38.29,308@-30.29,370@-18.86,444@-7.43,533@-4.00,640@-15.43 760@-26.29,913@-37.71,306@-30.86,367@-19.43,440@-8.00,528@-3.43,634@-14.86 754@-25.71,904@-37.14,303@-31.43,363@-20.00,436@-8.57,523@-2.86,628@-14.29 747@-25.14,896@-36.57,300@-32.00,360@-20.57,432@-9.14,519@-2.29,622@-13.71 740@-24.57,888@-36.00,297@-32.57,357@-21.14,428@-9.71,514@-1.71,617@-13.14 733@-24.00,880@-35.43,295@-33.14,354@-21.71,424@-10.29,509@-1.14,611@-12.57 727@-23.43,872@-34.86,292@-33.71,350@-22.29,420@-10.86,505@-0.57,605@-12.00 720@-22.86,864@-34.29,289@-34.29,347@-22.86,417@-11.43,500@-0.00,600@-11.43 713@-22.29,856@-33.71,287@-34.86,344@-23.43,413@-12.00,495@-0.57,595@-10.86 707@-21.71,848@-33.14,284@-35.43,341@-24.00,409@-12.57,491@-1.14,589@-10.29 701@-21.14,841@-32.57,282@-36.00,338@-24.57,405@-13.14,487@-1.71,584@-9.71 694@-20.57,833@-32.00,279@-36.57,335@-25.14,402@-13.71,482@-2.29,579@-9.14 688@-20.00,826@-31.43,276@-37.14,332@-25.71,398@-14.29,478@-2.86,573@-8.57 682@-19.43,818@-30.86,274@-37.71,329@-26.29,394@-14.86,473@-3.43,568@-8.00 675@-18.86,811@-30.29,271@-38.29,326@-26.86,391@-15.43,469@-4.00,563@-7.43 669@-18.29,803@-29.71,269@-38.86,323@-27.43,387@-16.00,465@-4.57,558@-6.86 663@-17.71,796@-29.14,267@-39.43,320@-28.00,384@-16.57,461@-5.14,553@-6.29 657@-17.14,789@-28.57,264@-40.00,317@-28.57,380@-17.14,456@-5.71,548@-5.71 651@-16.57,782@-28.00,938@-39.43,314@-29.14,377@-17.71,452@-6.29,543@-5.14 645@-16.00,774@-27.43,929@-38.86,311@-29.71,373@-18.29,448@-6.86,538@-4.57 640@-15.43,767@-26.86,921@-38.29,308@-30.29,370@-18.86,444@-7.43,533@-4.00 634@-14.86,760@-26.29,913@-37.71,306@-30.86,367@-19.43,440@-8.00,528@-3.43 628@-14.29,754@-25.71,904@-37.14,303@-31.43,363@-20.00,436@-8.57,523@-2.86 622@-13.71,747@-25.14,896@-36.57,300@-32.00,360@-20.57,432@-9.14,519@-2.29 617@-13.14,740@-24.57,888@-36.00,297@-32.57,357@-21.14,428@-9.71,514@-1.71 611@-12.57,733@-24.00,880@-35.43,295@-33.14,354@-21.71,424@-10.29,509@-1.14 605@-12.00,727@-23.43,872@-34.86,292@-33.71,350@-22.29,420@-10.86,505@-0.57 600@-11.43,720@-22.86,864@-34.29,289@-34.29,347@-22.86,417@-11.43,500@-0.00 595@-10.86,713@-22.29,856@-33.71,287@-34.86,344@-23.43,413@-12.00,495@-0.57 589@-10.29,707@-21.71,848@-33.14,284@-35.43,341@-24.00,409@-12.57,491@-1.14 584@-9.71,701@-21.14,841@-32.57,282@-36.00,338@-24.57,405@-13.14,487@-1.71 579@-9.14,694@-20.57,833@-32.00,279@-36.57,335@-25.14,402@-13.71,482@-2.29 573@-8.57,688@-20.00,826@-31.43,276@-37.14,332@-25.71,398@-14.29,478@-2.86 568@-8.00,682@-19.43,818@-30.86,274@-37.71,329@-26.29,394@-14.86,473@-3.43 563@-7.43,675@-18.86,811@-30.29,271@-38.29,326@-26.86,391@-15.43,469@-4.00 558@-6.86,669@-18.29,803@-29.71,269@-38.86,323@-27.43,387@-16.00,465@-4.57 553@-6.29,663@-17.71,796@-29.14,267@-39.43,320@-28.00,384@-16.57,461@-5.14 548@-5.71,657@-17.14,789@-28.57,264@-40.00,317@-28.57,380@-17.14,456@-5.71 543@-5.14,651@-16.57,782@-28.00,938@-39.43,314@-29.14,377@-17.71,452@-6.29 538@-4.57,645@-16.00,774@-27.43,929@-38.86,311@-29.71,373@-18.29,448@-6.86 533@-4.00,640@-15.43,767@-26.86,921@-38.29,308@-30.29,370@-18.86,444@-7.43 528@-3.43,634@-14.86,760@-26.29,913@-37.71,306@-30.86,367@-19.43,440@-8.00 523@-2.86,628@-14.29,754@-25.71,904@-37.14,303@-31.43,363@-20.00,436@-8.57 519@-2.29,622@-13.71,747@-25.14,896@-36.57,300@-32.00,360@-20.57,432@-9.14 514@-1.71,617@-13.14,740@-24.57,888@-36.00,297@-32.57,357@-21.14,428@-9.71 509@-1.14,611@-12.57,733@-24.00,880@-35.43,295@-33.14,354@-21.71,424@-10.29 505@-0.57,605@-12.00,727@-23.43,872@-34.86,292@-33.71,350@-22.29,420@-10.86 500@-0.00,600@-11.43,720@-22.86,864@-34.29,289@-34.29,347@-22.86,417@-11.43 495@-0.57,595@-10.86,713@-22.29,856@-33.71,287@-34.86,344@-23.43,413@-12.00 491@-1.14,589@-10.29,707@-21.71,848@-33.14,284@-35.43,341@-24.00,409@-12.57 487@-1.71,584@-9.71,701@-21.14,841@-32.57,282@-36.00,338@-24.57,405@-13.14 482@-2.29,579@-9.14,694@-20.57,833@-32.00,279@-36.57,335@-25.14,402@-13.71 478@-2.86,573@-8.57,688@-20.00,826@-31.43,276@-37.14,332@-25.71,398@-14.29 473@-3.43,568@-8.00,682@-19.43,818@-30.86,274@-37.71,329@-26.29,394@-14.86 469@-4.00,563@-7.43,675@-18.86,811@-30.29,271@-38.29,326@-26.86,391@-15.43 465@-4.57,558@-6.86,669@-18.29,803@-29.71,269@-38.86,323@-27.43,387@-16.00 461@-5.14,553@-6.29,663@-17.71,796@-29.14,267@-39.43,320@-28.00,384@-16.57 456@-5.71,548@-5.71,657@-17.14,789@-28.57,264@-40.00,317@-28.57,380@-17.14 452@-6.29,543@-5.14,651@-16.57,782@-28.00,938@-39.43,314@-29.14,377@-17.71 448@-6.86,538@-4.57,645@-16.00,774@-27.43,929@-38.86,311@-29.71,373@-18.29 444@-7.43,533@-4.00,640@-15.43,767@-26.86,921@-38.29,308@-30.29,370@-18.86 440@-8.00,528@-3.43,634@-14.86,760@-26.29,913@-37.71,306@-30.86,367@-19.43 436@-8.57,523@-2.86,628@-14.29,754@-25.71,904@-37.14,303@-31.43,363@-20.00 432@-9.14,519@-2.29,622@-13.71,747@-25.14,896@-36.57,300@-32.00,360@-20.57 428@-9.71,514@-1.71,617@-13.14,740@-24.57,888@-36.00,297@-32.57,357@-21.14 424@-10.29,509@-1.14,611@-12.57,733@-24.00,880@-35.43,295@-33.14,354@-21.71 420@-10.86,505@-0.57,605@-12.00,727@-23.43,872@-34.86,292@-33.71,350@-22.29 417@-11.43,500@-0.00,600@-11.43,720@-22.86,864@-34.29,289@-34.29,347@-22.86 413@-12.00,495@-0.57,595@-10.86,713@-22.29,856@-33.71,287@-34.86,344@-23.43 409@-12.57,491@-1.14,589@-10.29,707@-21.71,848@-33.14,284@-35.43,341@-24.00 405@-13.14,487@-1.71,584@-9.71,701@-21.14,841@-32.57,282@-36.00,338@-24.57 402@-13.71,482@-2.29,579@-9.14,694@-20.57,833@-32.00,279@-36.57,335@-25.14 398@-14.29,478@-2.86,573@-8.57,688@-20.00,826@-31.43,276@-37.14,332@-25.71 394@-14.86,473@-3.43,568@-8.00,682@-19.43,818@-30.86,274@-37.71,329@-26.29 391@-15.43,469@-4.00,563@-7.43,675@-18.86,811@-30.29,271@-38.29,326@-26.86 387@-16.00,465@-4.57,558@-6.86,669@-18.29,803@-29.71,269@-38.86,323@-27.43 384@-16.57,461@-5.14,553@-6.29,663@-17.71,796@-29.14,267@-39.43,320@-28.00 380@-17.14,456@-5.71,548@-5.71,657@-17.14,789@-28.57,264@-40.00,317@-28.57 377@-17.71,452@-6.29,543@-5.14,651@-16.57,782@-28.00,938@-39.43,314@-29.14 373@-18.29,448@-6.86,538@-4.57,645@-16.00,774@-27.43,929@-38.86,311@-29.71 370@-18.86,444@-7.43,533@-4.00,640@-15.43,767@-26.86,921@-38.29,308@-30.29 367@-19.43,440@-8.00,528@-3.43,634@-14.86,760@-26.29,913@-37.71,306@-30.86 363@-20.00,436@-8.57,523@-2.86,628@-14.29,754@-25.71,904@-37.14,303@-31.43 360@-20.57,432@-9.14,519@-2.29,622@-13.71,747@-25.14,896@-36.57,300@-32.00 357@-21.14,428@-9.71,514@-1.71,617@-13.14,740@-24.57,888@-36.00,297@-32.57 354@-21.71,424@-10.29,509@-1.14,611@-12.57,733@-24.00,880@-35.43,295@-33.14 350@-22.29,420@-10.86,505@-0.57,605@-12.00,727@-23.43,872@-34.86,292@-33.71 347@-22.86,417@-11.43,500@-0.00,600@-11.43,720@-22.86,864@-34.29,289@-34.29 344@-23.43,413@-12.00,495@-0.57,595@-10.86,713@-22.29,856@-33.71,287@-34.86 341@-24.00,409@-12.57,491@-1.14,589@-10.29,707@-21.71,848@-33.14,284@-35.43 338@-24.57,405@-13.14,487@-1.71,584@-9.71,701@-21.14,841@-32.57,282@-36.00 335@-25.14,402@-13.71,482@-2.29,579@-9.14,694@-20.57,833@-32.00,279@-36.57 332@-25.71,398@-14.29,478@-2.86,573@-8.57,688@-20.00,826@-31.43,276@-37.14 329@-26.29,394@-14.86,473@-3.43,568@-8.00,682@-19.43,818@-30.86,274@-37.71 326@-26.86,391@-15.43,469@-4.00,563@-7.43,675@-18.86,811@-30.29,271@-38.29 323@-27.43,387@-16.00,465@-4.57,558@-6.86,669@-18.29,803@-29.71,269@-38.86 320@-28.00,384@-16.57,461@-5.14,553@-6.29,663@-17.71,796@-29.14,267@-39.43 317@-28.57,380@-17.14,456@-5.71,548@-5.71,657@-17.14,789@-28.57,264@-40.00 314@-29.14,377@-17.71,452@-6.29,543@-5.14,651@-16.57,782@-28.00,938@-39.43 311@-29.71,373@-18.29,448@-6.86,538@-4.57,645@-16.00,774@-27.43,929@-38.86 308@-30.29,370@-18.86,444@-7.43,533@-4.00,640@-15.43,767@-26.86,921@-38.29 306@-30.86,367@-19.43,440@-8.00,528@-3.43,634@-14.86,760@-26.29,913@-37.71 303@-31.43,363@-20.00,436@-8.57,523@-2.86,628@-14.29,754@-25.71,904@-37.14 300@-32.00,360@-20.57,432@-9.14,519@-2.29,622@-13.71,747@-25.14,896@-36.57 297@-32.57,357@-21.14,428@-9.71,514@-1.71,617@-13.14,740@-24.57,888@-36.00 295@-33.14,354@-21.71,424@-10.29,509@-1.14,611@-12.57,733@-24.00,880@-35.43 292@-33.71,350@-22.29,420@-10.86,505@-0.57,605@-12.00,727@-23.43,872@-34.86 289@-34.29,347@-22.86,417@-11.43,500@-0.00,600@-11.43,720@-22.86,864@-34.29 287@-34.86,344@-23.43,413@-12.00,495@-0.57,595@-10.86,713@-22.29,856@-33.71 284@-35.43,341@-24.00,409@-12.57,491@-1.14,589@-10.29,707@-21.71,848@-33.14 282@-36.00,338@-24.57,405@-13.14,487@-1.71,584@-9.71,701@-21.14,841@-32.57 279@-36.57,335@-25.14,402@-13.71,482@-2.29,579@-9.14,694@-20.57,833@-32.00 276@-37.14,332@-25.71,398@-14.29,478@-2.86,573@-8.57,688@-20.00,826@-31.43 274@-37.71,329@-26.29,394@-14.86,473@-3.43,568@-8.00,682@-19.43,818@-30.86 271@-38.29,326@-26.86,391@-15.43,469@-4.00,563@-7.43,675@-18.86,811@-30.29 269@-38.86,323@-27.43,387@-16.00,465@-4.57,558@-6.86,669@-18.29,803@-29.71 267@-39.43,320@-28.00,384@-16.57,461@-5.14,553@-6.29,663@-17.71,796@-29.14 264@-40.00,317@-28.57,380@-17.14,456@-5.71,548@-5.71,657@-17.14,789@-28.57 siggen-2.3.10/tones.eg/tt.sh0000755000175000017500000000043707340001006014221 0ustar jjfamily#!/bin/sh # demo prog to test a base sample set...... # f=hole_bucket.notes if [ "$1" = "" ]; then echo "Usage: $0 SAMPLE_NAME" echo " where samples are in the file ./samples/SAMPLE_NAME.wav" exit -1 fi while [ "$1" != "" ]; do ../tones -load samples/$1.wav $1 $f shift done siggen-2.3.10/tones.eg/shepard-risset-rising.tones0000600000175000017500000002476707076065303020557 0ustar jjfamilyecho Rising Shepard-Risset scale ......... echo midfreq=500.000Hz number of partials is 7 echo density=1.200 number of frequency shifts=20 echo Freq range is 264.141Hz - 946.465Hz a bandwidth of 682.324Hz 264@-40.00,317@-28.57,380@-17.14,456@-5.71,548@-5.71,657@-17.14,789@-28.57 267@-39.43,320@-28.00,384@-16.57,461@-5.14,553@-6.29,663@-17.71,796@-29.14 269@-38.86,323@-27.43,387@-16.00,465@-4.57,558@-6.86,669@-18.29,803@-29.71 271@-38.29,326@-26.86,391@-15.43,469@-4.00,563@-7.43,675@-18.86,811@-30.29 274@-37.71,329@-26.29,394@-14.86,473@-3.43,568@-8.00,682@-19.43,818@-30.86 276@-37.14,332@-25.71,398@-14.29,478@-2.86,573@-8.57,688@-20.00,826@-31.43 279@-36.57,335@-25.14,402@-13.71,482@-2.29,579@-9.14,694@-20.57,833@-32.00 282@-36.00,338@-24.57,405@-13.14,487@-1.71,584@-9.71,701@-21.14,841@-32.57 284@-35.43,341@-24.00,409@-12.57,491@-1.14,589@-10.29,707@-21.71,848@-33.14 287@-34.86,344@-23.43,413@-12.00,495@-0.57,595@-10.86,713@-22.29,856@-33.71 289@-34.29,347@-22.86,417@-11.43,500@-0.00,600@-11.43,720@-22.86,864@-34.29 292@-33.71,350@-22.29,420@-10.86,505@-0.57,605@-12.00,727@-23.43,872@-34.86 295@-33.14,354@-21.71,424@-10.29,509@-1.14,611@-12.57,733@-24.00,880@-35.43 297@-32.57,357@-21.14,428@-9.71,514@-1.71,617@-13.14,740@-24.57,888@-36.00 300@-32.00,360@-20.57,432@-9.14,519@-2.29,622@-13.71,747@-25.14,896@-36.57 303@-31.43,363@-20.00,436@-8.57,523@-2.86,628@-14.29,754@-25.71,904@-37.14 306@-30.86,367@-19.43,440@-8.00,528@-3.43,634@-14.86,760@-26.29,913@-37.71 308@-30.29,370@-18.86,444@-7.43,533@-4.00,640@-15.43,767@-26.86,921@-38.29 311@-29.71,373@-18.29,448@-6.86,538@-4.57,645@-16.00,774@-27.43,929@-38.86 314@-29.14,377@-17.71,452@-6.29,543@-5.14,651@-16.57,782@-28.00,938@-39.43 317@-28.57,380@-17.14,456@-5.71,548@-5.71,657@-17.14,789@-28.57,264@-40.00 320@-28.00,384@-16.57,461@-5.14,553@-6.29,663@-17.71,796@-29.14,267@-39.43 323@-27.43,387@-16.00,465@-4.57,558@-6.86,669@-18.29,803@-29.71,269@-38.86 326@-26.86,391@-15.43,469@-4.00,563@-7.43,675@-18.86,811@-30.29,271@-38.29 329@-26.29,394@-14.86,473@-3.43,568@-8.00,682@-19.43,818@-30.86,274@-37.71 332@-25.71,398@-14.29,478@-2.86,573@-8.57,688@-20.00,826@-31.43,276@-37.14 335@-25.14,402@-13.71,482@-2.29,579@-9.14,694@-20.57,833@-32.00,279@-36.57 338@-24.57,405@-13.14,487@-1.71,584@-9.71,701@-21.14,841@-32.57,282@-36.00 341@-24.00,409@-12.57,491@-1.14,589@-10.29,707@-21.71,848@-33.14,284@-35.43 344@-23.43,413@-12.00,495@-0.57,595@-10.86,713@-22.29,856@-33.71,287@-34.86 347@-22.86,417@-11.43,500@-0.00,600@-11.43,720@-22.86,864@-34.29,289@-34.29 350@-22.29,420@-10.86,505@-0.57,605@-12.00,727@-23.43,872@-34.86,292@-33.71 354@-21.71,424@-10.29,509@-1.14,611@-12.57,733@-24.00,880@-35.43,295@-33.14 357@-21.14,428@-9.71,514@-1.71,617@-13.14,740@-24.57,888@-36.00,297@-32.57 360@-20.57,432@-9.14,519@-2.29,622@-13.71,747@-25.14,896@-36.57,300@-32.00 363@-20.00,436@-8.57,523@-2.86,628@-14.29,754@-25.71,904@-37.14,303@-31.43 367@-19.43,440@-8.00,528@-3.43,634@-14.86,760@-26.29,913@-37.71,306@-30.86 370@-18.86,444@-7.43,533@-4.00,640@-15.43,767@-26.86,921@-38.29,308@-30.29 373@-18.29,448@-6.86,538@-4.57,645@-16.00,774@-27.43,929@-38.86,311@-29.71 377@-17.71,452@-6.29,543@-5.14,651@-16.57,782@-28.00,938@-39.43,314@-29.14 380@-17.14,456@-5.71,548@-5.71,657@-17.14,789@-28.57,264@-40.00,317@-28.57 384@-16.57,461@-5.14,553@-6.29,663@-17.71,796@-29.14,267@-39.43,320@-28.00 387@-16.00,465@-4.57,558@-6.86,669@-18.29,803@-29.71,269@-38.86,323@-27.43 391@-15.43,469@-4.00,563@-7.43,675@-18.86,811@-30.29,271@-38.29,326@-26.86 394@-14.86,473@-3.43,568@-8.00,682@-19.43,818@-30.86,274@-37.71,329@-26.29 398@-14.29,478@-2.86,573@-8.57,688@-20.00,826@-31.43,276@-37.14,332@-25.71 402@-13.71,482@-2.29,579@-9.14,694@-20.57,833@-32.00,279@-36.57,335@-25.14 405@-13.14,487@-1.71,584@-9.71,701@-21.14,841@-32.57,282@-36.00,338@-24.57 409@-12.57,491@-1.14,589@-10.29,707@-21.71,848@-33.14,284@-35.43,341@-24.00 413@-12.00,495@-0.57,595@-10.86,713@-22.29,856@-33.71,287@-34.86,344@-23.43 417@-11.43,500@-0.00,600@-11.43,720@-22.86,864@-34.29,289@-34.29,347@-22.86 420@-10.86,505@-0.57,605@-12.00,727@-23.43,872@-34.86,292@-33.71,350@-22.29 424@-10.29,509@-1.14,611@-12.57,733@-24.00,880@-35.43,295@-33.14,354@-21.71 428@-9.71,514@-1.71,617@-13.14,740@-24.57,888@-36.00,297@-32.57,357@-21.14 432@-9.14,519@-2.29,622@-13.71,747@-25.14,896@-36.57,300@-32.00,360@-20.57 436@-8.57,523@-2.86,628@-14.29,754@-25.71,904@-37.14,303@-31.43,363@-20.00 440@-8.00,528@-3.43,634@-14.86,760@-26.29,913@-37.71,306@-30.86,367@-19.43 444@-7.43,533@-4.00,640@-15.43,767@-26.86,921@-38.29,308@-30.29,370@-18.86 448@-6.86,538@-4.57,645@-16.00,774@-27.43,929@-38.86,311@-29.71,373@-18.29 452@-6.29,543@-5.14,651@-16.57,782@-28.00,938@-39.43,314@-29.14,377@-17.71 456@-5.71,548@-5.71,657@-17.14,789@-28.57,264@-40.00,317@-28.57,380@-17.14 461@-5.14,553@-6.29,663@-17.71,796@-29.14,267@-39.43,320@-28.00,384@-16.57 465@-4.57,558@-6.86,669@-18.29,803@-29.71,269@-38.86,323@-27.43,387@-16.00 469@-4.00,563@-7.43,675@-18.86,811@-30.29,271@-38.29,326@-26.86,391@-15.43 473@-3.43,568@-8.00,682@-19.43,818@-30.86,274@-37.71,329@-26.29,394@-14.86 478@-2.86,573@-8.57,688@-20.00,826@-31.43,276@-37.14,332@-25.71,398@-14.29 482@-2.29,579@-9.14,694@-20.57,833@-32.00,279@-36.57,335@-25.14,402@-13.71 487@-1.71,584@-9.71,701@-21.14,841@-32.57,282@-36.00,338@-24.57,405@-13.14 491@-1.14,589@-10.29,707@-21.71,848@-33.14,284@-35.43,341@-24.00,409@-12.57 495@-0.57,595@-10.86,713@-22.29,856@-33.71,287@-34.86,344@-23.43,413@-12.00 500@-0.00,600@-11.43,720@-22.86,864@-34.29,289@-34.29,347@-22.86,417@-11.43 505@-0.57,605@-12.00,727@-23.43,872@-34.86,292@-33.71,350@-22.29,420@-10.86 509@-1.14,611@-12.57,733@-24.00,880@-35.43,295@-33.14,354@-21.71,424@-10.29 514@-1.71,617@-13.14,740@-24.57,888@-36.00,297@-32.57,357@-21.14,428@-9.71 519@-2.29,622@-13.71,747@-25.14,896@-36.57,300@-32.00,360@-20.57,432@-9.14 523@-2.86,628@-14.29,754@-25.71,904@-37.14,303@-31.43,363@-20.00,436@-8.57 528@-3.43,634@-14.86,760@-26.29,913@-37.71,306@-30.86,367@-19.43,440@-8.00 533@-4.00,640@-15.43,767@-26.86,921@-38.29,308@-30.29,370@-18.86,444@-7.43 538@-4.57,645@-16.00,774@-27.43,929@-38.86,311@-29.71,373@-18.29,448@-6.86 543@-5.14,651@-16.57,782@-28.00,938@-39.43,314@-29.14,377@-17.71,452@-6.29 548@-5.71,657@-17.14,789@-28.57,264@-40.00,317@-28.57,380@-17.14,456@-5.71 553@-6.29,663@-17.71,796@-29.14,267@-39.43,320@-28.00,384@-16.57,461@-5.14 558@-6.86,669@-18.29,803@-29.71,269@-38.86,323@-27.43,387@-16.00,465@-4.57 563@-7.43,675@-18.86,811@-30.29,271@-38.29,326@-26.86,391@-15.43,469@-4.00 568@-8.00,682@-19.43,818@-30.86,274@-37.71,329@-26.29,394@-14.86,473@-3.43 573@-8.57,688@-20.00,826@-31.43,276@-37.14,332@-25.71,398@-14.29,478@-2.86 579@-9.14,694@-20.57,833@-32.00,279@-36.57,335@-25.14,402@-13.71,482@-2.29 584@-9.71,701@-21.14,841@-32.57,282@-36.00,338@-24.57,405@-13.14,487@-1.71 589@-10.29,707@-21.71,848@-33.14,284@-35.43,341@-24.00,409@-12.57,491@-1.14 595@-10.86,713@-22.29,856@-33.71,287@-34.86,344@-23.43,413@-12.00,495@-0.57 600@-11.43,720@-22.86,864@-34.29,289@-34.29,347@-22.86,417@-11.43,500@-0.00 605@-12.00,727@-23.43,872@-34.86,292@-33.71,350@-22.29,420@-10.86,505@-0.57 611@-12.57,733@-24.00,880@-35.43,295@-33.14,354@-21.71,424@-10.29,509@-1.14 617@-13.14,740@-24.57,888@-36.00,297@-32.57,357@-21.14,428@-9.71,514@-1.71 622@-13.71,747@-25.14,896@-36.57,300@-32.00,360@-20.57,432@-9.14,519@-2.29 628@-14.29,754@-25.71,904@-37.14,303@-31.43,363@-20.00,436@-8.57,523@-2.86 634@-14.86,760@-26.29,913@-37.71,306@-30.86,367@-19.43,440@-8.00,528@-3.43 640@-15.43,767@-26.86,921@-38.29,308@-30.29,370@-18.86,444@-7.43,533@-4.00 645@-16.00,774@-27.43,929@-38.86,311@-29.71,373@-18.29,448@-6.86,538@-4.57 651@-16.57,782@-28.00,938@-39.43,314@-29.14,377@-17.71,452@-6.29,543@-5.14 657@-17.14,789@-28.57,264@-40.00,317@-28.57,380@-17.14,456@-5.71,548@-5.71 663@-17.71,796@-29.14,267@-39.43,320@-28.00,384@-16.57,461@-5.14,553@-6.29 669@-18.29,803@-29.71,269@-38.86,323@-27.43,387@-16.00,465@-4.57,558@-6.86 675@-18.86,811@-30.29,271@-38.29,326@-26.86,391@-15.43,469@-4.00,563@-7.43 682@-19.43,818@-30.86,274@-37.71,329@-26.29,394@-14.86,473@-3.43,568@-8.00 688@-20.00,826@-31.43,276@-37.14,332@-25.71,398@-14.29,478@-2.86,573@-8.57 694@-20.57,833@-32.00,279@-36.57,335@-25.14,402@-13.71,482@-2.29,579@-9.14 701@-21.14,841@-32.57,282@-36.00,338@-24.57,405@-13.14,487@-1.71,584@-9.71 707@-21.71,848@-33.14,284@-35.43,341@-24.00,409@-12.57,491@-1.14,589@-10.29 713@-22.29,856@-33.71,287@-34.86,344@-23.43,413@-12.00,495@-0.57,595@-10.86 720@-22.86,864@-34.29,289@-34.29,347@-22.86,417@-11.43,500@-0.00,600@-11.43 727@-23.43,872@-34.86,292@-33.71,350@-22.29,420@-10.86,505@-0.57,605@-12.00 733@-24.00,880@-35.43,295@-33.14,354@-21.71,424@-10.29,509@-1.14,611@-12.57 740@-24.57,888@-36.00,297@-32.57,357@-21.14,428@-9.71,514@-1.71,617@-13.14 747@-25.14,896@-36.57,300@-32.00,360@-20.57,432@-9.14,519@-2.29,622@-13.71 754@-25.71,904@-37.14,303@-31.43,363@-20.00,436@-8.57,523@-2.86,628@-14.29 760@-26.29,913@-37.71,306@-30.86,367@-19.43,440@-8.00,528@-3.43,634@-14.86 767@-26.86,921@-38.29,308@-30.29,370@-18.86,444@-7.43,533@-4.00,640@-15.43 774@-27.43,929@-38.86,311@-29.71,373@-18.29,448@-6.86,538@-4.57,645@-16.00 782@-28.00,938@-39.43,314@-29.14,377@-17.71,452@-6.29,543@-5.14,651@-16.57 789@-28.57,264@-40.00,317@-28.57,380@-17.14,456@-5.71,548@-5.71,657@-17.14 796@-29.14,267@-39.43,320@-28.00,384@-16.57,461@-5.14,553@-6.29,663@-17.71 803@-29.71,269@-38.86,323@-27.43,387@-16.00,465@-4.57,558@-6.86,669@-18.29 811@-30.29,271@-38.29,326@-26.86,391@-15.43,469@-4.00,563@-7.43,675@-18.86 818@-30.86,274@-37.71,329@-26.29,394@-14.86,473@-3.43,568@-8.00,682@-19.43 826@-31.43,276@-37.14,332@-25.71,398@-14.29,478@-2.86,573@-8.57,688@-20.00 833@-32.00,279@-36.57,335@-25.14,402@-13.71,482@-2.29,579@-9.14,694@-20.57 841@-32.57,282@-36.00,338@-24.57,405@-13.14,487@-1.71,584@-9.71,701@-21.14 848@-33.14,284@-35.43,341@-24.00,409@-12.57,491@-1.14,589@-10.29,707@-21.71 856@-33.71,287@-34.86,344@-23.43,413@-12.00,495@-0.57,595@-10.86,713@-22.29 864@-34.29,289@-34.29,347@-22.86,417@-11.43,500@-0.00,600@-11.43,720@-22.86 872@-34.86,292@-33.71,350@-22.29,420@-10.86,505@-0.57,605@-12.00,727@-23.43 880@-35.43,295@-33.14,354@-21.71,424@-10.29,509@-1.14,611@-12.57,733@-24.00 888@-36.00,297@-32.57,357@-21.14,428@-9.71,514@-1.71,617@-13.14,740@-24.57 896@-36.57,300@-32.00,360@-20.57,432@-9.14,519@-2.29,622@-13.71,747@-25.14 904@-37.14,303@-31.43,363@-20.00,436@-8.57,523@-2.86,628@-14.29,754@-25.71 913@-37.71,306@-30.86,367@-19.43,440@-8.00,528@-3.43,634@-14.86,760@-26.29 921@-38.29,308@-30.29,370@-18.86,444@-7.43,533@-4.00,640@-15.43,767@-26.86 929@-38.86,311@-29.71,373@-18.29,448@-6.86,538@-4.57,645@-16.00,774@-27.43 938@-39.43,314@-29.14,377@-17.71,452@-6.29,543@-5.14,651@-16.57,782@-28.00 siggen-2.3.10/tones.eg/clementine.notes0000600000175000017500000000115407075604030016430 0ustar jjfamily# # example tune .... clementine ...... :100 b3,g3,0:295 0,0,0:5 b3,g3,0:95 0,0,0:5 b3,g3,g1:400 g3,d3,d2:400 d4,b3,g2:295 0,0,g2:5 d4,b3,g2:95 0,0,g2:5 d4,b3,g1:400 b3,g3,d2:395 0,0,d2:5 g3,g3,g2:195 0,0,g2:5 g3,b3,g2:195 0,0,g2:5 g3,d4,g1:400 g3,d4,d2:195 0,0,d2:5 g3,d4,d2:200 a3,c4,g2:200 b3,b3,g2:200 c4,a3,d2:400 c4,a3,f#2:395 0,0,f#2:5 c4,a3,a2:200 d4,b3,a2:200 e4,c4,c2:395 0,0,c2:5 e4,c4,e2:395 0,0,e2:5 d4,b3,a2:300 c#4,a3,a2:100 d4,b3,g2:400 b3,g3,b2:395 0,0,b2:5 d4,g3,b3:200 d4,b3,b3:200 c4,a3,d2:400 c4,a3,f#2:195 0,0,f#2:5 c4,d3,f#2:200 d4,f#2,c3:200 c4,a3,c3:200 b3,g3,g1:400 b3,g3,g2,d2:400 siggen-2.3.10/tones.eg/randnote.sh0000700000175000017500000000015407340022322015372 0ustar jjfamily#! /bin/sh # # demo to show use of randtone tones=../tones ./randnote c4 250 100 | $tones -v -i - sin 100 siggen-2.3.10/tones.eg/slide.sh0000755000175000017500000000061707340022406014701 0ustar jjfamily#!/bin/sh # # Demo run to create and then play a shepard-risset sliding scale..... r=shepard-risset-rising.tones f=shepard-risset-falling.tones #echo "creating rising-slide tones specification file at $t ....." #./shepard-risset 700 7 1.2 15 -50 > $t echo "Now playing ./$r and ./$f ........" ../tones -c 9 :200 sin ./$r ./$f # use this line with verbose output.... #tones -c 9 -v :200 ./$r ./$f siggen-2.3.10/tones.eg/shepard-risset.c0000600000175000017500000000613306725546026016351 0ustar jjfamily/* shepard-risset.c * generate indefinitely rising/descending tones sequence/amplitude * to feed to tones program. * * Usage: shepard-risset mid-freq partials density shifts [db] * * mid-freq specifies the middle freq. * partials is the number of seperate frequencies in the mixture * density ratio between partials * shifts is the number of freq shifts to create * [db] optional attenuation in dB at the edges * * Problems........... * with the dB values going positive and oscillating. * Initial values are correct - it's the amendment for successive shifts * * also need to loop a total of partial blocks of shifts specs! */ #include #include #include #define MAXSHIFTS 100 #define MAXPARTIALS 50 #define DEFDB -40.0 double midfreq,density,minf,maxf; int partials,shifts; help(e) int e; { puts("\ Usage: shepard-risset mid-freq partials density shifts [-db]\n\ \n\ generate indefinitely rising/descending tones sequence/amplitude\n\ to feed to tones program.\n\ \n\ mid-freq specifies the middle freq.\n\ partials is the number of seperate frequencies in the mixture\n\ density ratio between partials\n\ shifts is the number of freq shifts to create\ "); printf("-db optional - number of db down at limits, default %.2fdb\n",DEFDB); printf("\nmid-freq must be >= 100Hz, partials >=3 and < %d,\n shifts >=3 and < %d, and density>0\n", MAXPARTIALS, MAXSHIFTS); return(0); } main(argc,argv) int argc; char **argv; { int i,j,k,l,m,n,N; double x,y,z,f,sr; double db,dbi,Dbs[MAXPARTIALS*MAXSHIFTS]; int freqs[MAXPARTIALS*MAXSHIFTS]; argv++; argc--; if (argc!=4 && argc!=5) exit(help(1)); midfreq=strtod(argv[0],NULL); partials=atoi(argv[1]); density=strtod(argv[2],NULL); shifts=atoi(argv[3]); db=DEFDB; if (argc==5) db=strtod(argv[4],NULL); printf("echo midfreq=%.3fHz number of partials is %d\n",midfreq,partials); printf("echo density=%.3f number of frequency shifts=%d\n",density,shifts); if (midfreq<100.0 || partials<3 || partials>MAXPARTIALS || shifts<3 || shifts>MAXSHIFTS || density<=0) { printf("mid freq must be >= 100Hz, partials >=3 and < %d,\n shifts >=3 and < %d, and density > 0", MAXPARTIALS, MAXSHIFTS); exit(1); } maxf=midfreq*pow(density,((double)partials)/2.0); minf=midfreq/pow(density,((double)partials)/2.0); printf("echo Freq range is %.3fHz - %.3fHz a bandwidth of %.3fHz\n", minf,maxf,maxf-minf); N=shifts*partials; sr=pow(density,1/(double)shifts); /* ratio for freq increase for each shift */ if (db>0) db=-db; dbi=(2.0*-db)/(double)(N); for (i=0,x=db,f=minf; i main(argc,argv) int argc; char **argv; { int i,f,d,N; argv++; argc--; if (argc<1 || argc>3) { printf("Usage: randtone freq [duration [num_tones]]\n"); printf("\n duration is in millisecs (def. 250), default num_tones is 1000.\n"); exit(1); } d=250; N=1000; f=atoi(*argv); argv++; argc--; if (argc) { d=atoi(*argv++); argc--; if (argc) { N=atoi(*argv); } } srandom(time(NULL)%(d+f)); for (i=0; i5000)?(10000-f):f); d=d+(random()%200)-100; d=(d<25)?(50-d):((d>1000)?(2000-d):d); } } siggen-2.3.10/tones.eg/dtmf0000700000175000017500000000077306720514340014117 0ustar jjfamily#! /bin/sh # # Usage: dtmf singledigit(s) # # example: dtmf 0 1 1 3 6 6 6 6 if [ -x ../tones ] ; then t="../tones" else t=tones fi t="$t sin :150" while [ "$1" != "" ]; do case $1 in 0) t="$t 941,1336 " ;; 1) t="$t 697,1209 " ;; 2) t="$t 697,1336 " ;; 3) t="$t 697,1477 " ;; 4) t="$t 770,1209 " ;; 5) t="$t 770,1336 " ;; 6) t="$t 770,1477 " ;; 7) t="$t 852,1209 " ;; 8) t="$t 852,1336 " ;; 9) t="$t 852,1477 " ;; esac t="$t 0,0:70" shift done $t siggen-2.3.10/tones.eg/ramp.c0000600000175000017500000000132206474565544014355 0ustar jjfamily/* ramp.c * output sequential number from start to end * reepeatedly! * * Usage: ramp [start [end]] * * Default values are 200 and 2000 */ #include #define START 200 #define END 2000 #define STEP 1 #define LOOPS 10 main(argc,argv) int argc; char **argv; { int d,step,i,st,end,l; st=START; end=END; step=STEP; l=LOOPS; argc--; argv++; if (argc) { argc--; st=atoi(*argv++); if (argc) { argc--; end=atoi(*argv++); if (argc) { argc--; step=atoi(*argv++); if (argc) { argc--; l=atoi(*argv++); } } } } d=(st>end); if (d) step=-step; for (; l-- ; ) { for (i=st; (d)?(i>=end):(i<=end); i+=step) printf("%d\n",i); } } siggen-2.3.10/tones.eg/README.tones0000600000175000017500000001126507340022254015243 0ustar jjfamily Some notes on the 'tones' program. Jim Jackson ---------------------------------- May 1999 The tones program has growed out of a simple sequential tone generator that I wrote for Michael Meifert for generating a sequence of tones for control purposes. Since then I've expanded it to maintain a set of 'channels', each channel having a seperately configured waveform, frequency and intensities. All the channels are mixed to provide the output signal. Mark E. Shoulson provided a base patch for adding intensity levels. However this showed up bugs in the digital mixer which have now been fixed and the amplitude handling much expanded - see the relevant sections in the manual page. Musical note generation Also I've added the ability to generate musical notes, by being able to specify a note + optional sharp + octave digit, e.g. C3 is middle C. The tuning is based on the standard concert A of 440Hz (A3), and an equally tempered scale. Thanks to Ivor Dykes for the music lessons! If you want a different tuning then the frequencies are defined in an array in tonesgen.c, and can easily be altered to taste. Thanks also to Robert P. Hanssen for pointing out a correction to the freq. numbers used for generating named notes. Some examples tones 2000 sin c3,e3,g3 plays the C Major chord tones 100 sin 941,1336 0,0 697,1209 0,0 697,1209 0,0 697,1477 0,0 generate the dtmf dial tones for '0' '1' '1' '3' Here are the frequencies to use..... 1 = 697,1209 2 = 697,1336 3 = 697,1477 4 = 770,1209 5 = 770,1336 6 = 770,1477 7 = 852,1209 8 = 852,1336 9 = 852,1477 0 = 941,1336 * = 941,1209 # = 941,1477 tones -loop :2000 sin 1000 square 1000 tri 1000 saw 1000 0 generate a series of test waveforms repeatedly. The ':' infront of the default duration setting forces this to be a duration setting even on the loop - otherwise it would be treated as a freq. spec. Yeah it's a bug - but I couldn't see an easy fix. More examples in the tones.eg directory In sub-directory, tones.eg, there are some examples using the tones program. Run make in the tones.eg directory to create the programs ramp, randtone, randnote and shepard-risset, and create some more complex loadable waveforms in the tones.eg/samples directory. Then try the shell scripts ramp.sh, randtone.sh, randnote.sh, slide.sh (the shepard-risset sliding scale) and tune.sh . ramp.sh generate a slow ramp modulated frequency. Edit the script to change the parameters. 'ramp' simple generates a suitable series of incrementing (or decrementing) numbers that tones converts into successive short tones. randtone.sh generates random tones of varying duration. randnote.sh generates random notes slide.sh creates and plays a sample shepard-risset sliding scale tt.sh plays "There's a hole in my bucket" using the loadable waveform given as a parameter to the script. tune.sh plays a couple of tunes! File hole_bucket.notes contains the notes for a simple tune. clementine.notes contains the notesi for a more complex tune with harmony (clementine). Just for fun. dtmf script to create dtmf dial tones for single digits given as parameters to the script. e.g. dtmf 0 1 1 3 6 6 6 shepard-risset is a C program to generate tones commands for generating Shepard-Risset sliding tones - often called elevator sounds because they appear to be moving up (or down) permanently. Try this: % shepard-risset 700 7 1.2 15 -50 > /usr/tmp/slide % tones -c 7 -v -l :200 /usr/tmp/slide or just run the slide.sh script. It uses precomputed sequences for rising and falling elevator sounds. Read the C code or run shepard-risset with no arguments to see what the parameters are. See paper http://www.acm.org/sigchi/chi96/proceedings/shortpap/Beaudoin-Lafon/Mbl_txt.htm for more some more details on shepard-risset tones. Installation of the stuff in tones.eg You can run 'make' in the tones.eg directory and then run the example shell scripts. e.g. % cd tones.eg % make % ./tune.sh If you wish, you can copy the scripts into a suitable directory, your own ~/bin directory or /usr/local/bin. You will have to edit the scripts to put in the location of the tones program - usually /usr/local/bin. The only script worth installing really is 'dtmf' - and I'm sure that can be improved! Feel free - let me know the results. Jim Jackson jj@comp.leeds.ac.uk School of Computer Studies University of Leeds UK siggen-2.3.10/tones.eg/randtone.sh0000700000175000017500000000015207340017471015401 0ustar jjfamily#! /bin/sh # # demo to show use of randtone tones=../tones ./randtone 500 250 100 | $tones -i - sin 100 siggen-2.3.10/tones.eg/Makefile0000600000175000017500000000213407075613426014703 0ustar jjfamily# # Makefile for jj's siggen tones.eg files ..... SHELL = /bin/sh # Edit PROGS to make the programs you want. You may wish to omit smix # if you do not want yet another mixer program. PROGS = randtone randnote ramp shepard-risset # Edit SAMPLES to make the 1Hz + harmonic mixes to simulate different # instrument tones. SAMPLES = flute organ # srcdir = . includedir = /usr/include/ncurses INSDIR = /usr/local/bin MANDIR = /usr/local/man/man1 LOCALINS = $(HOME)/bin LOCALMAN = $(HOME)/man/man1 CC = gcc CFLAGS = -O2 CPPFLAGS = -I. -I$(includedir) CCFLAGS = $(CFLAGS) $(CPPFLAGS) LINK = $(CC) LDFLAGS = -lncurses -lgpm -lm .c.o: $(CC) -c $(CCFLAGS) $< all: $(PROGS) (cd samples ; make ) %.txt: %.1 nroff -man $< | col -b -x > $@ randtone: randtone.o $(CC) $@.o -o $@ randnote: randnote.o $(CC) $@.o -o $@ ramp: ramp.o $(CC) $@.o -o $@ shepard-risset: shepard-risset.o $(CC) $@.o -o $@ -lm flute: $@.notes ../tones -ch 20 -i $@.tones -w samples/$@.wav -v organ: ../tones -ch 20 -i $@.tones -w samples/$@.wav -v clean: rm -rf *.o $(PROGS) *~ ( cd samples ; make clean ) siggen-2.3.10/tones.eg/hole_bucket.notes0000600000175000017500000000044707075601377016610 0ustar jjfamily# # sample tune to be played by the tones program..... :200 g3:200 a3:190 0:10 b3:390 0:10 d3:390 0:10 d3:390 0:10 e3:400 g3:400 d3:400 e3:400 g3:400 d3:400 e3:400 g3:400 g3:200 a3:190 0:10 b3:390 0:10 d3:390 0:10 d3:390 0:10 e3:400 g3:400 d3:400 e3:400 g3:390 0:10 a3:395 0:5 g3:800 siggen-2.3.10/siggen.10000644000175000017500000002024011011657010013043 0ustar jjfamily.TH siggen 1 "20 Aug 1999" "Release 2" "Linux System Manual" .SH NAME .I siggen \- an Ncurses based signal generator program .SH SYNOPSIS .IP siggen\ [options]\ [waveform\ [freq]] .SH DESCRIPTION .I siggen is a simple signal generator program, with an Ncurses based user interface, that can digitally generate standard waveforms on the LINUX /dev/dsp device. 8 or 16 bit samples can be generated depending on the hardware. .PP .I siggen allows two independant waveforms to be generated. In stereo the two signals appear on different channels. In mono the two signals are digitally mixed onto the one mono channel. .PP The frequency is specified as an integer number of Hertz. Fractional Hertz frequencies are not supported. Of course, only frequencies less than half the samplerate (number of samples/sec) are accurately meaningful. Higher frequencies can be specified, but don't expect to hear them! .PP On screen values for individual fields can be locked to prevent accidental changes. The unlock facility unlocks all locked fields. .PP Corresponding values for the 2 channels can be set to track, the values are made equal and a change to one causes a change to the other. e.g. making the frequency values track will make both channels the same frequency, and altering one freq. value alters both simultaneously. .PP The waveforms that can be generated are: .IP sine A standard sine wave .IP cosine a sine wave with a 90 degree phase shift .IP square a standard square wave with a 50% mark space ratio .IP triangle a linear rise from 0 to peak, thru' 0 to negative peak, and back to 0 .IP sawtooth a ramp waveform with 'infinitely' fast flyback (:-) An ideal oscilloscope timebase signal. .IP noise This is weak. All it consists of is one second of pseudo-randomly generated samples, played repeatedly. I'd love to do proper white/pink noise, but I don't know enough, and I don't think the structure of the program is conducive to accurate noise generation. .IP pulse A square waveform where the mark/space ratio (as a percentage) can be specified. The default value is 10% (mark/space ratio of 1:9). .PP A lot of thought has gone into the algorithms for generating the waveforms. I believe the sin/cos wave to be very pure (modulo your sound card :-), but I don't have access to a THD meter to measure it. For best signal accuracy leave the gain setting at 100(%). The generator will then make the wave's peak value fit the maximum digital values allowed. Use a mixer program to control the output volume, or an external attenuator. .PP The gain factor option can be useful for simulating a signal that has been subject to clipping, by specifing a gain of > 100%. In fact a trapezoid signal can be made by generating a clipped sawtooth wave. The greater the gain, the closer the signal approaches a square wave (the rise and fall times decrease). .PP .I siggen ordinarily generates one seconds worth of 1 Hz samples at the specified samplerate, for each waveform, and generates frequency F by circularly sampling every Fth sample. Each buffer fragment is generated for the parameter(s) set at that moment. Buffer fragment sizes are set so that aprox. 10 fragments/sec are generated. Changing a generation parameter, e.g. waveform, frequency, gain, will impact the next buffer fragment generated, and hence changes appear to be almost immediate. .PP The .I -res option can be used to make siggen generate signals with 0.1Hz resolution, or 0.01Hz resolution. However .I be\ warned at 0.1Hz resolution the basic waveform sample buffers generated are each 10 times (and at 0.01Hz resolution 100 times) as big as the samplerate. It typically requires 5.5Mbytes of memory to run at 0.1Hz resolution, 16bit 32000 samples/sec. and 55Mbytes of memory to run at 0.01Hz resolution. Because of the large buffer sizes, the initial waveform calculation time can also be lengthy. Remember also that the waveforms are re-calculated whenever the playing parameters, 8/16bit, mono/stereo, samplerate are changed. .PP If your sounds periodically 'breaks' up with clicks or breaks, it is usually a sign that siggen is not being scheduled sufficiently often. Either increase the priority (see .I nice et al.), kill off other processes, get a faster processor, or increase the number of audio buffer fragments that siggen uses. This last will make siggen respond more sluggishly to changes in generation parameters. .I syslogd and .I crond are two processes that I've found useful to kill off - YMMV. .IP Defaults output to /dev/dsp, 22050 samples/sec, stereo if stereo card else mono, 16 bit samples if possible, else 8 bit, 3 audio buffer fragments. .SH CONFIGURATION\ FILES .PP Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. .PP All the siggen suite of programs are compiled with the names of the config files built in. By default the configuration files are: .IP ./.siggen.conf is the LOCAL config file. .IP $HOME/.siggen.conf is the HOME config file. .IP /etc/siggen.conf is the GLOBAL config file. .IP siggen\ -h will indicate which config files will be searched for. .PP The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. .PP The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. .PP If no configuration files exist, the program provides builtin default values, and most of these values can be set by appropriate command line switches and flags. .PP See siggen.conf(5) for details of the configuration files. .PP .I siggen looks for configuration values BUFFERSPERSEC, CHANNELS, DACFILE, FRAGMENTS, RESOLUTION, SAMPLERATE, SAMPLESIZE, VERBOSE, VI_KEYS. .IP BUFFERSPERSEC The aprox. number of sound buffer fragments to play every second (Sound buffersize is always a power of 2). .IP CHANNELS sets the number of channels, see '-c' option. .IP DACFILE allows the name of the DAC/DSP/PCM device to be changed from /dev/dsp .IP FRAGMENTS The number of Audio Buffers to configure in the driver. .IP RESOLUTION The minimum change possible to the frequency setting. Only 3 values allowed: 1Hz , 0.1Hz or 0.01Hz .IP SAMPLERATE sets the number of samples/sec for the DAC device .IP SAMPLESIZE sets whether 8 or 16 bit samples to be generated .IP VERBOSE sets whether or not to run in verbose mode. .IP VI_KEYS if set then the VI cursor moving keys "HJKL" are enabled .SH OPTIONS .IP -h display usage and help info .IP -BPS\ n configure to play aprox. n audio buffers per second. .IP -C\ configfile Use configfile as the LOCAL configuration file. .IP -NB\ n set number of audio buffers to n .IP -v be verbose .IP -s\ samples generate with samplerate of samples/sec .IP -8|-16\ or\ -b\ 8|16 force 8 bit or 16 bit mode. .IP -1|-2 mono or stereo .IP -res\ n set resolution of frequency generation. Valid values are: 1Hz, 0.l1Hz or 0.01Hz .SH EXAMPLES .SH .SH FILES .SH .SH SEE ALSO sgen, swgen, tones, sweepgen, siggen.conf .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/fsynth.c0000600000175000017500000001743311011656443013177 0ustar jjfamily/* fsynth.c * Ncurses based fourier waveform synthesiser * * Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* * fsynth : * * 1Hz sample buffers are created. * A waveform is built up dymanically, by adding into the * fundamental Freq F the specified amounts of the various harmonics N*F * The generation method is to sample the 1Hz samples at intervals * of the required frequencies. * * History: * 26Oct98 V1.0 Built by modifying the siggen.c and sigscr.c * to give the basic framework * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fsynth.h" #define MAXPRM 32 #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) int vflg,dflg,vikeys; int DAC; /* File Handle for DSP */ unsigned int samplerate; /* Samples/sec */ unsigned int afmt; /* format for DSP */ unsigned int stereo; int Bufspersec; /* number of sounds fragments per second */ int Nfragbufs; /* number of driver frag buffers */ int fragsize; /* size of driver buffer fragments */ int fragsamplesize; /* size of fragments in samples */ /* Fundamental Freq details */ char wf[32]="sine"; /* waveform type */ unsigned int freq=440; /* signal frequency */ int channels; /* number of generating channels */ char *sys; char *configfile; char dac[130]; help(e) int e; { char **aa; fprintf(stderr,VERSTR,sys,VERSION); fputs("\nUsage: \n 1: fsynth [flags] [waveform [freq]]]\n",stderr); #ifdef HAVE_DAC_DEVICE fprintf(stderr,"Defaults: SINE wave, %d harmonics, output to %s, %d samples/sec,\n", DEF_FSYNTH_CHANNELS,DAC_FILE,SAMPLERATE); fputs(" 16 bit mono samples if possible, else 8 bit.\n",stderr); #else fprintf(stderr,"Defaults: SINE wave, %d harmonics, %d samples/sec,\n", DEF_FSYNTH_CHANNELS,SAMPLERATE); fputs(" 16 bit mono samples. Must be used with -o or -w option.\n",stderr); #endif fputs("Valid waveforms are:",stderr); for ( aa=(char **)getWavNames(); *aa; aa++ ) fprintf(stderr," %s",*aa); fputs("\nflags: -s samples generate with samplerate of samples/sec\n",stderr); fputs(" -8/-16 or -b 8|16 force 8 bit or 16 bit mode.\n",stderr); fputs(" -c channels number of harmonics or channels\n",stderr); fputs(" -C file use file as local configuration file\n",stderr); fputs(" -NB n Numer of Buffers to create is n, def. is 3\n",stderr); fputs(" -BPS n Number of Buffers to play per sec, def. is 15\n",stderr); return(e); } /* main * */ main(argc,argv) int argc; char **argv; { unsigned int v[MAXPRM],maxv,i,j,k,l,m,n,N; FILE *f; char *p,bf[130]; int c; unsigned int t; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; samplerate=0; afmt=AFMT_QUERY; Nfragbufs=0; Bufspersec=0; vflg=dflg=0; channels=0; stereo=0; while (argc && **argv=='-') { /* all flags and options must come */ n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (chkword(1,"samplerate")) { if (argc && isdigit(**argv)) { samplerate=atoi(*argv++); argc--; } } else if (chkword(2,"NB")) { if (argc && isdigit(**argv)) { Nfragbufs=atoi(*argv++); argc--; } } else if (chkword(3,"BPS")) { /* Buffers played per second - defines size */ if (argc && isdigit(**argv)) { Bufspersec=atoi(*argv++); argc--; } } else if (chkword(2,"16")) { afmt=AFMT_S16_LE; } else if (chkword(1,"bits")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i==8) afmt=AFMT_U8; else if (i==16) afmt=AFMT_S16_LE; else exit(err_rpt(EINVAL,"must be '-b 8' or '-b 16'.")); } else if (chkword(1,"Config")) { if (argc && **argv != '-') { configfile=*argv++; argc--; } } else if (chkword(1,"channels")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i<2) exit(err_rpt(EINVAL,"Must have 2 or more harmonics (channels).")); channels=i; } else { /* check for single char. flags */ for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='8') afmt=AFMT_U8; else if (*p=='d') dflg=1; else if (*p=='v') vflg++; else { *bf='-'; *(bf+1)=*p; *(bf+2)=0; exit(help(err_rpt(EINVAL,bf))); } } } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (samplerate==0) { samplerate=atoi(get_conf_value(sys,"samplerate",QSAMPLERATE)); } if (channels==0) { channels=atoi(get_conf_value(sys,"channels",QDEF_FSYNTH_CHANNELS)); } if (Nfragbufs==0) { Nfragbufs=atoi(get_conf_value(sys,"fragments",QDEFAULT_FRAGMENTS)); } if (Bufspersec==0) { Bufspersec=atoi(get_conf_value(sys,"buffspersec",QDEFAULT_BUFFSPERSEC)); } if (afmt==AFMT_QUERY) { afmt=atoi(get_conf_value(sys,"samplesize",QAFMT_QUERY)); } strncpy(dac,get_conf_value(sys,"dacfile",DAC_FILE),sizeof(dac)-1); vikeys=atoi(get_conf_value(sys,"vi_keys",QVI_KEYS)); /* OK now check is waveform is specified on command line... */ if (argc) { strncpy(wf,*argv++,32); wf[31]=0; argc--; /* waveform type */ if (argc) { freq=atoi(*argv++); argc--; if (argc) exit(help(err_rpt(EINVAL,"Too many parameters"))); } } /* if no format specified then try 16 bit */ i=afmt; if ((DAC=DACopen(dac,"w",&samplerate,&i,&stereo))<0) { exit(err_rpt(errno,"Opening DSP for output.")); } if ((afmt!=AFMT_QUERY) && (i!=afmt)) { exit(err_rpt(EINVAL,"Sound card doesn't support format requested.")); } afmt=i; if ((fragsize=setfragsize(DAC,Nfragbufs,Bufspersec,samplerate,afmt,stereo))<0) { exit(err_rpt(errno,"Problem setting appropriate fragment size.")); } fragsamplesize=(fragsize>>(afmt==AFMT_S16_LE))>>(stereo); if (freq > samplerate/2) { fprintf(stderr,"%d Hz is more than half the sampling rate\n",freq); exit(err_rpt(EINVAL,"Frequency setting too great")); } if (vflg) { printf("Mono %s bit samples being generated.\n",(afmt==AFMT_S16_LE)?"16":"8"); printf("Playing at %d samples/sec\n",samplerate); printf("%d Buffer fragments of %d bytes (%d samples). Aprox. %d millisecs.\n", Nfragbufs,fragsize, fragsamplesize, 1000*((fragsize>>(stereo))>>(afmt==AFMT_S16_LE))/samplerate); printf("Requested %d buffers/sec and have %d buffs/sec\n",Bufspersec, (samplerate+(fragsamplesize/2))/fragsamplesize); printf("\n\n"); getchar(); } WinGen(DAC); close(DAC); exit(0); } siggen-2.3.10/mixer.h0000600000175000017500000000302411011656303012777 0ustar jjfamily/* mixer.h * mixer control header file * Jim Jackson */ /* * Copyright (C) 2000-2008 Jim Jackson jj@franjam.org.uk */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #ifndef _mixer__h #define _mixer__h #ifdef __FreeBSD__ #include #else #include #endif /* Define some functions..... */ #define IS_MIX_INPUT_DEV(N) (recmask&(1<<(N))) #define IS_MIX_DEV(N) (devmask&(1<<(N))) #define IS_MIX_DEV_STEREO(N) (stereodevs&(1<<(N))) #define IS_MIX_SOURCE(N) (sources&(1<<(N))) #define MIX_DEV_NAME(N) (devname[N]) #define GET_MIX_VALUE(D,V) (ioctl(mixFD, MIXER_READ(D), &V)) #define SET_MIX_VALUE(D,V) (ioctl(mixFD, MIXER_WRITE(D), &V)) /* extern declarations of some variables. */ extern int mixFD,devmask,recmask,sources,stereodevs; extern char *devname[]; #endif /* _mixer__h */ siggen-2.3.10/fsynth.h0000600000175000017500000000176711011652324013201 0ustar jjfamily/* fsynth.h * header file for the Ncurses based fourier synth * Jim Jackson May 2008 */ #include "config.h" #define VERSTR "%s Ver. %s Ncurses based Fourier Waveform Synthesiser" extern int vflg,dflg,vikeys; extern char *sys; extern char dac[]; /* name of output device */ extern int DAC; extern unsigned int samplerate; /* Samples/sec */ extern unsigned int stereo; /* stereo mono */ extern unsigned int afmt; /* format for DSP */ extern int Bufspersec; /* Number of Buffers per sec */ extern int Nfragbufs; /* number of driver buffers */ extern int fragsize; /* size of driver buffer fragments */ extern int fragsamplesize; /* size of fragments in samples */ extern char wf[32]; /* waveform type */ extern unsigned int freq; /* signal frequency */ extern int channels; /* number of harmonics */ siggen-2.3.10/TODO0000600000175000017500000000051411011657226012200 0ustar jjfamilyadd 0.1 and 0.01 HZ resolution to siggen and sweepgen Should be possible - add a new configuration param RESOLUTION with values of 1 10 or 100. double check. all manual pages - especially siggen, sweepgen and fsynth I've improved siggen - do similar for sweepgen and fsynth. Add loading of custom waveforms. oh boy yes. siggen-2.3.10/siggen.c0000600000175000017500000003042711011656534013137 0ustar jjfamily/* siggen.c * Ncurses based Signal generator, 16/8 bit, 2 channels if stereo card, * Emulates usual functions of a lab sig. gen. generating sine, square, * triangle, sawtooth, pulse, noise waveforms, along with loadable * waveforms. * * Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* * siggen : * * A one second's worth buffer of samples is maintained (samplerate samples) * for each channel. These are mixed into a 1 second play buffer * that in play mode is played in a circular fashion. By keeping freq. * as an integer number of Hertz there is always an exact number of full * cycles in 1 sec, so the 1 sec play buffer start and finish match * seamlessly. If only mono card then the two channels are mixed into * one playing channel. * * * History: * 2002 V1.6 Added fractional frequency settings, can be setup to * generate freq. in 1Hz, 0.1Hz or 0.01Hz resolution * 1999 V1.5 Added ability for settings for one channel to track the * settings on the other channel, e.g. setting different * waveforms, and setting tracking in one of the freq fields * allows simultaneous changing of the freqs * of both channels. 't' or 'T' toggles tracking on/off. * Also added a feature to "fix" or "lock" certain fields * The values in these locked fields cannot be changed and * are skipped over when tabbing from field to field. * Pressing 'l', 'L' or '!' while in a field locks it. * 'u' or 'U' unlocks all fields, so that the values can * be changed. If VI keys are enabled only '!' locks. * Check config.h * 20May97 V1.4 Tidied up generation, and added phase offset for * second channel with respect to first channel. * Added 'R' key to resync the two channels, in case * phase was off because of playing different frequencies * 13May97 V1.3 Changed IO library in order to action single key * presses on fields, so that we can generate sound * all the time and key actions take 'immediate' effect. * i.e. continuous playing. Generation changed to sampling * every F'th sample from a 1Hz set of samples to create * samples for a frequency of F Hz. * 15Mar97 V1.2 Pulse not working - fixed by changing default ratio and * ratio2 from 0 to -1, forces generator() to pick up def. value * --Feb97 V1.1 Various screen changes - help line, some tweeking * of ncfio key handling etc. * --Jan97 V1.0 2 channels - if stereo support, then each chan. * is fed to a seperate stereo output. If only mono * is possible then the two channels are mixed into the * one output. * While entering details of function required * the program ceases playing any previously generated * samples. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "siggen.h" #define MAXPRM 32 #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) int vflg,dflg,vikeys; int resolution; /* Freq. resolution for signal generation * 1 for 1Hz res ; 10 for 0.1Hz res; * 100 for 0.01Hz res */ int DAC; /* File Handle for DSP */ unsigned int samplerate; /* Samples/sec */ unsigned int stereo; /* stereo mono */ unsigned int afmt; /* format for DSP */ int Bufspersec; /* number of sounds fragments per second */ int Nfragbufs; /* number of driver frag buffers */ int fragsize; /* size of driver buffer fragments */ int fragsamplesize; /* size of fragments in samples */ int LWn; /* number of specified loadable waveforms */ char **LWaa; /* array of specifed loadable waveforms */ /* channel 1 ... */ char wf[32]="sine"; /* waveform type */ unsigned int freq=440; /* signal frequency */ int ratio=-1; /* used in pulse, sweep etc */ int Gain=1000; /* Amplification factor Samples are scaled by Gain/1000 */ /* channel 2 ... */ char wf2[32]="off"; /* waveform type */ unsigned int freq2=440; /* signal frequency */ int ratio2=-1; /* used in pulse, sweep etc */ int Gain2=1000; /* Amplification factor see above */ int phase=0; /* phase difference of chan2 from chan1 */ char *sys; char *configfile; char dac[130]; help(e) int e; { char **aa; fprintf(stderr,VERSTR,sys,VERSION); fputs("\nUsage: siggen [flags] [waveform [freq [param]]]\n",stderr); #ifdef HAVE_DAC_DEVICE fprintf(stderr,"Defaults: SINE wave, output to %s, %d samples/sec,\n", DAC_FILE,SAMPLERATE); fputs(" 16 bit stereo samples if possible, else 8 bit and/or mono.\n",stderr); #else fprintf(stderr,"Defaults: SINE wave, %d samples/sec,\n",SAMPLERATE); fputs(" 16 bit mono samples. Must be used with -o or -w option.\n",stderr); #endif fputs("Valid waveforms are:",stderr); for ( aa=(char **)getWavNames(); *aa; aa++ ) fprintf(stderr," %s",*aa); fputs("\n",stderr); fprintf(stderr,"Default Config files are \"%s\", \"$HOME/%s\" and\n\"%s\", searched in that order.\n", DEF_CONF_FILENAME, DEF_CONF_FILENAME, DEF_GLOBAL_CONF_FILE); fputs("flags: -s samples generate with samplerate of samples/sec\n",stderr); fputs(" -8/-16 or -b 8|16 force 8 bit or 16 bit mode.\n",stderr); fputs(" -1,-2 force mono or stereo (1 or 2 channels)\n",stderr); fputs(" -NB n Number of Buffers to create is n, def. is 3\n",stderr); fputs(" -BPS n Number of Buffers to play per sec, def. is 15\n",stderr); /* fputs(" -load wave_file load waveform from wav_file\n",stderr);*/ fputs(" -res n n=1, 0.1 or 0.01 - frequency resolution\n",stderr); return(e); } /* main * */ main(argc,argv) int argc; char **argv; { unsigned int v[MAXPRM],maxv,i,j,k,l,m,n,N; double d; FILE *f; char *p,bf[130]; int c; unsigned int t; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; samplerate=0; afmt=AFMT_QUERY; LWn=0; LWaa=argv; Nfragbufs=0; Bufspersec=0; vflg=dflg=0; stereo=-1; resolution=0; while (argc && **argv=='-') { /* all flags and options must come */ n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (chkword(1,"samplerate")) { if (argc && isdigit(**argv)) { samplerate=atoi(*argv++); argc--; } } else if (chkword(2,"NB")) { /* Number of buffer fragments */ if (argc && isdigit(**argv)) { Nfragbufs=atoi(*argv++); argc--; } } else if (chkword(3,"BPS")) { /* Buffers played per second - defines size */ if (argc && isdigit(**argv)) { Bufspersec=atoi(*argv++); argc--; } } else if (chkword(2,"16")) { afmt=AFMT_S16_LE; } else if (chkword(1,"bits")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i==8) afmt=AFMT_U8; else if (i==16) afmt=AFMT_S16_LE; else exit(err_rpt(EINVAL,"must be '-b 8' or '-b 16'.")); } else if (chkword(1,"A")) { if (argc && isdigit(**argv)) { Gain=atoi(*argv++)*10; argc--; } } else if (chkword(3,"load")) { /* load a waveform */ if (argc) { LWaa[LWn++]=*argv++; argc--; } /* waveform file name */ } else if (chkword(3,"resolution")) { /* set freq generation resolution */ if (argc) { if ((resolution=set_resolution(*argv++))==0) { exit(err_rpt(EINVAL,"bad resolution value, must be 1, 0.1 or 0.01")); } argc--; } } else { /* check for single char. flags */ for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='1') stereo=0; else if (*p=='2') stereo=1; else if (*p=='8') afmt=AFMT_U8; else if (*p=='d') dflg=1; else if (*p=='v') vflg++; else { *bf='-'; *(bf+1)=*p; *(bf+2)=0; exit(help(err_rpt(EINVAL,bf))); } } } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (samplerate==0) { samplerate=atoi(get_conf_value(sys,"samplerate",QSAMPLERATE)); } if (stereo==-1) { stereo=atoi(get_conf_value(sys,"channels","1")); if (stereo) stereo--; } if (Nfragbufs==0) { Nfragbufs=atoi(get_conf_value(sys,"fragments",QDEFAULT_FRAGMENTS)); } if (resolution==0) { resolution=set_resolution(get_conf_value(sys,"resolution",DEFAULT_RESOLUTION)); if (resolution==0) { exit(err_rpt(EINVAL,"bad resolution value, must be 1, 0.1 or 0.01")); } } if (Bufspersec==0) { Bufspersec=atoi(get_conf_value(sys,"buffspersec",QDEFAULT_BUFFSPERSEC)); } if (afmt==AFMT_QUERY) { afmt=atoi(get_conf_value(sys,"samplesize",QAFMT_QUERY)); } strncpy(dac,get_conf_value(sys,"dacfile",DAC_FILE),sizeof(dac)-1); vikeys=atoi(get_conf_value(sys,"vi_keys",QVI_KEYS)); /* OK now check is waveform is specified on command line... */ if (argc) { strncpy(wf,*argv++,32); wf[31]=0; argc--; /* waveform type */ if (argc) { freq2=freq=atoi(*argv++); argc--; if (argc) { ratio=atoi(*argv++); argc--; } if (argc) exit(help(err_rpt(EINVAL,"Too many parameters"))); } } /* if no format specified then try 16 bit */ i=afmt; n=stereo; if ((DAC=DACopen(dac,"w",&samplerate,&i,&n))<0) { exit(err_rpt(errno,dac)); } if (((afmt!=AFMT_QUERY) && (i!=afmt)) || ((stereo!=-1) && (n!=stereo))) { exit(err_rpt(EINVAL,"Sound card doesn't support format requested.")); } afmt=i; stereo=n; if ((fragsize=setfragsize(DAC,Nfragbufs,Bufspersec,samplerate,afmt,stereo))<0) { exit(err_rpt(errno,"Problem setting appropriate fragment size.")); } fragsamplesize=(fragsize>>(afmt==AFMT_S16_LE))>>(stereo); if (freq > samplerate/2) { fprintf(stderr,"%d Hz is more than half the sampling rate!!!\n",freq); } if (vflg) { printf("%s %s bit samples being generated.\n", (stereo)?"Stereo, ":"Mono, ",(afmt==AFMT_S16_LE)?"16":"8"); printf("Samples amplified by a factor of %d/1000\n",Gain); printf("Playing at %d samples/sec\n",samplerate); printf("Frequency resolution is %.2fHz\n",1.0/resolution); printf("Initial Frequencies: ch1 %dHz ch2 %dHz\n",freq,freq2); printf("ch2 at a phase difference of %d degrees to ch1\n",phase); printf("Buffer fragment size is %d bytes (%d samples). Aprox. %d millisecs.\n", fragsize, fragsamplesize, 1000*((fragsize>>(stereo))>>(afmt==AFMT_S16_LE))/samplerate); printf("Requested %d buffers/sec and have %d buffs/sec\n",Bufspersec, (samplerate+(fragsamplesize/2))/fragsamplesize); printf("%d loadable waveforms specified.\n",LWn); } WinGen(DAC); close(DAC); exit(0); } set_resolution(p) char *p; { char *s; int r; double d; d=strtod(p,&s); r=0; if (d==1.0) r=1; else if (d==0.1) r=10; else if (d==0.01) r=100; return(r); } siggen-2.3.10/fsynscr.c0000600000175000017500000003130411011656430013340 0ustar jjfamily/* fsynscr.c * Screen handling for ncurses fsynth program * Jim Jackson Oct 99 */ /* * Copyright (C) 1997-2008 * Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #include #include #include #include "scfio.h" #include "fsynth.h" #include #define CARDLINE 8 #define F0LINE CARDLINE+1 #define Fsampl setV[0] #define Fbits setV[1] #define Fchans setV[2] #define FNFrag setV[3] #define Fwave CHvals[0] #define Ffreq CHvals[1] /* set number of millisecs to wait while checking for ESC sequences */ #define KEY_DELAY 25 /* set number of microsecs to wait if no keys pressed. Is kind to * other processes - we don't hog time */ #define NO_KEY_WAIT 25000 /* Main screen character strings............ */ char *hl[]={ " ====== /====\\ |\\ || ====== || || ", " || || ||\\ || || || || ", " |=== \\====\\ || \\ || || |=====| ", " || || | | || \\ || || || || ", " || \\====/ \\--| || \\|| || || || ", " | ", " Digital Fourier \\--/ Waveform Synthesiser ", " -----------------------------------------------------------------------------", NULL }; char *oh[]={ " /\\ ", " --/--\\--/-- ", " \\/ ", NULL }; char *sig=" Jim Jackson "; char VERS[128]; int Lsamplerate, /* Local copy of card params to prevent */ LNfb, Lafmt,Lstereo; /* playing being screwed while updating */ /* card characteristics. */ int fragtim; /* Playing Time of one fragment in Microsecs */ char Mstarting[]=" Starting up .......... ", Mwavef[]=" Waveform: ", Mfreq[]= " Frequency: ", McardL[]=" samples/sec x byte ms buffers", Mtime[12], Minfo[]=" : ", Mstereo[]="STEREO", Mmono[]= " MONO ", M16b[]= "16 bit", M8b[]= " 8 bit", Mmain[]= "Tab/Return next field,'Z'ero amplitudes,'R'esync chans,'Q'uit,'S'etup Card params", Mcard[]= "'S'et new values Tab/Return move to next field."; char *Mbits[]={ M8b, M16b, NULL }; char *Mchans[]={ Mmono, Mstereo, NULL }; struct SCField **CHvals; struct SCField *setV[6]; /* The variable card parameters */ struct SCField *Ftime,*Finfo,*Finfo2,*Ffrag,*Ffragtim; /* Help strings for second info line. */ char Hwav[]="DOWN ARROW (or SPACE) & UP ARROW to select WaveForm", Hnum[]="Enter Digits, DEL or <- to delete, LEFT/RIGHT move digits, UP/DOWN Inc/Dec", Hbits[]="Press to toggle 8 / 16 bit setting", Hchan[]="Press to toggle Mono / Stereo setting"; char **Hvals; char *Hset[]= { Hnum, Hbits, Hchan, Hnum, NULL }; /* waveform name and buffer array....... */ int *levels=NULL; /* array to hold harmonic levels */ char **WAVEFORMS=NULL; int **wavbufs=NULL; /* WinGen() The main interactive screen */ WinGen(fd) int fd; { int c,i,n,st,t; int f,savef; int card; /* if true we are altering the card params * if false we are inputing in the main screen */ char **helpMs; /* ptr to array of help msgs for info line */ struct SCField **inFs; /* ptr to arrays of current input fields * alternates between the card parameters * and the main screen input */ WinGenInit(); helpMs=Hvals; inFs=CHvals; doinfo(Mmain,0,Finfo2); savef=card=0; f=1; dispfield(inFs,helpMs,Finfo,f); refresh(); t=0; for (;;) { if ((i=time(NULL))-t) { t=i; dotime(Ftime); } /* update time every sec */ if (playsamples(fd)<0) { /* do any generation */ move(COLS-1,0); endwin(); return(err_rpt(errno,"Problem generating output samples.")); } if ((c=getch())==-1) { /* if no keypressed..... */ playsamples(fd); /* try to generate another buffer */ delay(NO_KEY_WAIT); /* then wait preset time - be kind */ continue; } if (c=='s' || c=='S') { /* enter or exit card parameter change */ if (card) { /* exit card param changes..... */ /* check if card params have changed - if so close and reopen */ Lafmt=(GetOptionIndex(Fbits))?AFMT_S16_LE:AFMT_U8; Lstereo=0; /* ignore setting force mono */ if ((Lsamplerate!=samplerate) || (Lafmt!=afmt) || (Lstereo!=stereo) || (LNfb!=Nfragbufs)) { close(fd); if ((fd=DACopen(dac,"w",&Lsamplerate,&Lafmt,&Lstereo))<0 || (fragsize=setfragsize(fd,LNfb,Bufspersec,Lsamplerate,Lafmt,Lstereo))<0) { move(COLS-1,0); endwin(); return(err_rpt(errno,"Opening DSP for output.")); } fragsamplesize=(fragsize>>(Lafmt==AFMT_S16_LE))>>(Lstereo); fragtim=fragsamplesize*1000000/Lsamplerate; putfield(Ffrag); putfield(Ffragtim); } dofields(setV); /* if samplerate or format has changed, re-generate waveforms */ if ((Lsamplerate!=samplerate) || (Lafmt!=afmt)) { if (st=genAllWaveforms(&WAVEFORMS,&wavbufs,1,Lsamplerate,Lafmt)) { move(COLS-1,0); endwin(); return(err_rpt(st,"Problem generating Base waveforms.")); } } samplerate=Lsamplerate; afmt=Lafmt; stereo=Lstereo; Nfragbufs=LNfb; SetOptionIndex(Fbits,(afmt==16)); SetOptionIndex(Fchans,stereo); playsamples(-1); /* reset/resync the 'generators' */ dispfield(inFs,helpMs,Finfo,f); /* update card param display */ card=0; f=savef; /* restore main screen field */ /* and turn off 'in card' flag */ inFs=CHvals; helpMs=Hvals; /* set main screen input and help */ doinfo(Mmain,0,Finfo2); /* and 2nd info line */ dispfield(inFs,helpMs,Finfo,f); /* and redisplay main screen */ } else { /* enter card setting alteration stuff */ dispfield(inFs,helpMs,Finfo,f); /* display main screen */ card=1; savef=f; /* save current position and */ /* set 'in card' flag */ inFs=setV; helpMs=Hset; /* set card input and help */ f=next_field(inFs,-1); /* find first valid input field */ doinfo(Mcard,0,Finfo2); dispfield(inFs,helpMs,Finfo,f); } continue; } if (c=='q' || c=='Q') { move(COLS-1,0); endwin(); return(c); } if (c=='r' || c=='R') { playsamples(-1); /* set generators for harmonics to be in phase */ continue; } if (c=='z' || c=='Z') { dispfield(inFs,helpMs,Finfo,f); levels[0]=10000; for ( i=1; iadj]); wpend=wv1+samplerate; fl=0; ff=1; for ( l=1, lp=levels; l<=channels ; l++, lp++ ) { freqn=l*freq; if (!(*lp) || freqn>=(samplerate/2)) { off[l-1]=(((off[l-1]*freqn)%samplerate)*fragsamplesize)%samplerate; continue; } wp=wv1+(of=off[l-1]); t=fl+((*lp)/ff); for (i=fragsamplesize, vp=(short int *)frag; i ; i--) { /* t=(int)(wv1[of1]); */ /* *vp++=(short int)((t>32767)?32767:((t<-32767)?-32767:t)); */ *vp++=(short int)((((int)(*vp)*fl)+(((int)(*wp))*(*lp))/ff)/t); wp=wv1+(of=(of+freqn)%samplerate); } off[l-1]=of; for ( fl=t ; fl>32000 ; fl>>=1, ff<<=1 ) { } } } else { /* afmt is 8 bit this is still to implement */ w1=(unsigned char *)(wavbufs[Fwave->adj]); for (i=0, p=frag; i255)?255:((t<0)?0:t)); of1=(of1+freq)%samplerate; */ } } if (write(fd,frag,fragsize)<0) return(-1); } return(0); } siggen-2.3.10/tones.10000644000175000017500000003373511011657067012750 0ustar jjfamily.TH tones 1 "20 Feb 1998" "Release 2.3" "Linux System Manual" .SH NAME .I tones \- a sequential tone generator program .SH SYNOPSIS .B tones [options] [waveform] T freq(s)|notes(s)|command_file(s) .SH DESCRIPTION .I tones generates one or more tones of various types (waveforms) and duration (T millisecs) of the specified frequencies or notes, or mixtures of frequencies or notes. See .I tones\ -h for a list of possible waveforms. The waveforms should include .I sine, .I cosine (90 degrees out of phase to sine), .I square (50% mark/space ratio), .I sawtooth (a ramp waveform), .I triangle and .I noise. Sine is the default. Besides the inbuilt waveforms, waveforms can be loaded from suitable WAV files - see below .I LOADABLE\ WAVEFORMS. .PP .I T is the default number of millisecs that each tone is to be played. Frequencies (freq(s)) are specified in Hertz as integers. A frequency of 0 causes T millisecs of silence to be played. Notes are specified as the musical note letter with an optional '#' to sharpen the note, then an octave number. Octaves run from C to C. Middle C is C3, the immediately preceding note is B2! The first Octave is from C0 to C1. .PP Several frequencies/notes can be played at once, by specifying the frequencies/notes required joined by a ',' character (but no spaces!). .PP e.g. .I 1000,1500,2000 specifies that the three frequencies are played together, all at the same relative level. See .I AMPLITUDES sections below for a discussion of how to set absolute amplitude levels or differing relative amplitudes for notes played together or serially. .PP Each freq specification can optionally contain a duration, by appending ':T', where 'T' is the duration in millisecs. This duration overrides the default. Also the default duration can be changed by using a the ':T' format on it's own - not appended to a freq spec. .PP e.g. .I 1200,600:1000 play the two freqs for 1 sec .PP e.g. .I c3,e3,g3 play the C major chord .PP e.g. .I :250 set the default tone duration to 250ms .PP Waveforms can be specified/altered at anytime. A single waveform name specifies that waveform to be used for all channels. Alternatively a comma (',') seperated list of waveforms can be given to specify or alter the waveform to use for a given channel. Ommitting a waveform in a list, means that the previous waveform is left unchanged. .PP e.g. .I square,,triangle specifies using square waves for chan 1, chan 2 is left unchanged, and triangular waves are used for channel 3. .PP The digital samples (either 8 or 16 bits) are played by default to the Linux .I /dev/dsp device at a samplerate of 22050 samples per second, in mono mode. (see .I CONFIGURATION\ FILES section below) .PP Fractional Hertz frequencies are not supported. Of course, only frequencies less than half the samplerate (number of samples/sec) can be accurately generated; but the program doesn't check this. .PP Instead of playing the output to .I /dev/dsp the samples can be written to a file as raw samples (-o file) or written in WAV format (-w wavfile). These data files can then be played back quickly with a raw data or WAV file player (e.g. wavplay) without the overhead of actually generating the samples. .PP There are some special 'commands' that can be specified, that may be useful in input files. .IP \:N Set default tone duration to N millisecs .IP \@N Set base amplitude level of tones when in absolute .I amplitude mode .IP absolute Set absolute amplitude mode (see below) .IP echo The rest of the line of the input file, or the rest of the command line parameter (NB to use quotes where necessary) is output to stdout. .IP relative Set relative amplitude mode (see below) .IP reset|resync All generator points are reset to the start of the waveform buffers. This forces subsequant generation of multiple frequencies/waveforms to be in phase. .PP Further, if the word is not one of the above, then tones checks to see if a file of that name exists, and if it does then the file is assumed to be a file of tones commands which are executed. .PP e.g. .I tones\ -v\ :100\ tune1\ tune2\ \ \ \ will interpret and play the tones commands in files .I tune1 and .I tune2. This file processing is recursive. Files of commands can execute other files of commands etc. As usual, .I '-' can be used to specify stdin. .SH RELATIVE\ AMPLITUDES .PP .I tones by default works in a 'relative' amplitude mode, where the output level and sample range are maximally maintained. This ensures the best signal accuracy. .PP When specifying multiple frequencies/notes to be played together, then the relative amplitudes can be specified in deciBells by appending "@db" to the note. .PP e.g. .I 440,880@-12,1760@-30 specifies a mixture with 880Hz -12dB down, and 1760Hz -30dB down relative to the level of 440Hz. The mixed signal samples will span the full 16 or 8 bit range permitted for maximal signal accuracy. .PP The dB levels indicate the relative power levels. .I -3dB being at a relative power level of 0.5, .I -20dB being at a relative power level of 0.01 . However power levels are proportional to the square of the signal amplitude. So a signal at -6dB (quarter power) will only have its amplitude down by half. To reduce a signal amplitude by 1/10 then specify -20dB, i.e. a power level down by a factor of a hundredth. .PP dB levels can be specified as decimal values. .SH ABSOLUTE\ AMPLITUDES .PP .I tones can work in an absolute amplitude mode, where signal power levels are specified in deciBells (dB) relative to a 0dB level that indicates a peak value of +32767/-32768 for 16 bit signed samples, and 255/0 for 8 bit unsigned values. Hence any signal at a positive dB level will be clipped. Signals at a negative dB level will attentuated. If no level is specified then 0dB is assumed. .PP e.g. .I 500@-20,750@-6,1000,-12 gives 500Hz at -20db (amplitude 0.1), 750Hz at -6db (amplitude 0.5), and 1000Hz at -12dB (amplitude 0.25). The final mixed signal will have an amplitude of 0.1 + 0.5 + 0.25 = 0.85 or -1.4dB. .PP As can be seen, there is no "hands-free" in .I absolute mode. You have to work out the dB levels yourself and ensure that the resultant mixed signal does not go above 0dB and get clipped. Remember also that a sine wave at -80dB down (amplitude 1/10000th) only has 6 digital levels and is a pretty poor representation of a sine wave, not suitable for post amplification and use! .PP In .I absolute mode the base 'zero' level can be altered at any time by use of the .I @dB command. All subsequent dB levels specified will have this base level added to them. .PP e.g. .I @-20\ 1000,1200@+6,1400@-6 is the same as 1000Hz at -20dB, 1200Hz at -14dB and 1400Hz at -26dB. .SH LOADABLE\ WAVEFORMS .PP Given that the generation method used by .I tones to generate a waveform of FHz is simply to sequentially select every Fth sample from a buffer containing S samples of one complete waveform at a frequency of 1Hz (treating the buffer as circular, the beginning conceptually joined to the end), where S is the number of samples per second, it is possible to load a customised waveform from a WAV file containing the S samples of a 1Hz waveform. See the .I -load\ WavFile and .I -lw\ N options below. The name of the waveform is taken as the basename of the WavFile, i.e. with any trailing '.suffix' and leading path removed. Each loaded waveform should hence have this name unique, and different from the inbuilt waveform names. .PP The samples in WavFile should be 16 bit, mono, of the same number of samples as tones' playing samplerate, e.g. if tones is playing at 32000 samples per sec then the WavFile should contain 32000 16 bit samples. 16 bit samples are needed, because tones works internally with 16 bit samples, even if it is feeding 8 bit samples to the sound card or output file. Ideally the samples should span one complete wavelength, i.e. represent 1 second of a 1Hz signal. However this can be varied if used with some intelligence. If, say, 1 seconds worth of 5Hz of the waveform is used, then the output frequency will be 5 times higher than specified. If you have a mixture of 3Hz and 5Hz samples, then the frequencies generated will be a mixture of 3 and 5 times the frequency specified. I hope that is all understandable! .PP See the .I tones.eg directory for some examples of loadable modules and how .I tones itself can be used to generate the loadable waveforms. .SH OPTIONS .IP -8\ |\ -b\ 8 set 8 bit unsigned data samples .IP -16\ |\ -b\ 16 set 16 bit signed little-endian data samples. .IP -abs|-absolute set absolute amplitude mode .IP -a when used in conjunction with the -o option, data is appended to the file. .IP -C\ file use "file" as the local configuration file (see below). .IP -c\ CHANNELS set the maximum number of channels (concurrent played frequencies) to CHANNELS. The default number is 4. There is some virtue in keeping the number of channels to a minimum. .IP -f when used in conjunction with the -o or -w options, any existing file is silently overwritten. .IP -h display usage and help info .IP -i\ file read frequencies/waveforms to generate from file 'file'. Reads from standard input if filename is '-'. Any command line specifications are actioned before the input file is read. .IP -l play the tone sequence repetitively. Forced off if writing samples to a file with the -o or -w options. .IP -loop\ N play the tone sequence N times. .IP -o\ file write out samples to a raw data file. You will have to remember the data format, e.g. samplerate and 8/16 bit. .IP -rel|-relative set relative amplitude mode .IP -s\ samplerate set the number of samples per second to samplerate. For many simple uses a samplerate of 8000 is sufficient, making any saved data files smaller. .IP -w\ wavfile write samples out in WAV format to wavfile. The WAV header contains details of whether the data is 8 or 16 bits and the sampling rate. You cannot use the append (-a) option with WAV files. .IP -v be verbose .IP -lw\ N Specify the number of loadable waveforms allowed, the default is 4 .IP -load\ WavFile Load the waveform from the WavFile. .SH EXAMPLES .IP tones\ 50\ 1000\ 700,1200\ 800,1100,1300 generates 3 50 millisecs sine tones, the first consisting of only 1000Hz, the second of 700Hz and 1200Hz and the third of 800Hz, 1100Hz and 1300Hz .IP tones\ -loop\ square\ 200\ 700\ 900\ 400\ 500 generates a sequence of 4 200 millisecs square wave tones which is repeated until the program is interupted. .IP tones\ -w\ seq.wav\ 70\ 1016\ 1200\ 1080\ 1150\ 1016 generates a sequence of 5 70 millisecs sine tones, and instead of playing them the samples are stored in WAV format in seq.wav which can be played by any WAV file player. .IP tones\ -w\ trap.wav\ :1000\ triangle\ absolute\ 1@6 Generates a WAV file .I trap.wav consisting of a trapezoid waveform where the rise and fall slopes take up half the wavelength. A sawtooth is generated with a maximum that has twice the amplitude of the maximum sample sizes allowed, hence it is clipped flat for half the waveform period making a trapezoid shape. .IP tones\ -load\ trap.wav\ :1000\ triangle\ 1000\ trap\ 500\ triangle\,trap\ 1000\,500 Will load the trapezoid waveform generated above as a new waveform called .I trap and then plays 1 seconds each of first a 1000Hz triangle wave, then a 500Hz .I trap waveform and finally both waveforms played together. .PP See also the .I tones.eg directory in the siggen distribution. .SH CONFIGURATION\ FILES .PP Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. .PP All the siggen suite of programs are compiled with the names of the config files built in. By default the configuration files are: .IP ./.siggen.conf is the LOCAL config file. .IP $HOME/.siggen.conf is the HOME config file. .IP /etc/siggen.conf is the GLOBAL config file. .IP tones\ -h will indicate which config files will be searched for. .PP The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. .PP The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. .PP If no configuration files exist, the program provides builtin default values, and most of these values can be set by appropriate command line switches and flags. .PP See siggen.conf(5) for details of the configuration files. .PP .I tones looks for configuration values CHANNELS, DACFILE, SAMPLERATE, SAMPLESIZE, VERBOSE, LOADABLE_WAVEFORMS. .IP CHANNELS sets the number of channels, see '-c' option. .IP DACFILE allows the name of the DAC/DSP/PCM device to be changed from /dev/dsp .IP LOADABLE_WAVEFORMS specifies the allowable number of loadable waveforms .IP SAMPLERATE sets the number of samples/sec for the DAC device .IP SAMPLESIZE sets whether 8 or 16 bit samples to be generated .IP VERBOSE sets whether or not to run in verbose mode. .SH SEE ALSO .IP siggen.conf(5),\ sgen(1),\ swgen(1) .SH .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/scfio.c0000600000175000017500000002776411011656504012775 0ustar jjfamily/* scfio.c * Single char. action structured field functions using ncurses. * Jim Jackson Apr 97 onwards */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* Some Bug fixes and reasons for non-obvious code.... * * Under solaris isprint() and isdigit() seem to ignore the parity bit * hence I have had to precede some of these tests with isascii() && ... * to make sure it worked right. * * To work right the keyboard routines need to be..... * * initscr(); noecho(); nonl(); intrflush(stdscr,FALSE); * keypad(stdscr,TRUE); halfdelay(3); * * To get it to work under solaris and xterm. */ /* * These functions are given a key character to action on a given field. * Either the key does something to the field or it doesn't. Either way * the value of the field always shows the current value. * * These functions are useful in screen based programs that may need to * schedule several things, one of which is single key input handling. * * Typical use is :- * * struct SCField *FS; * * while { * if (keypress()) { * c=getchar(); * if (c==XXX) { .... do any special key handling .... } * else { * c=actfield(c,FS); * ..... * } * } * do_other_things(); * } * * See tfch.c for demo of use. * * In absence of any manual/documentation here is a brief summary * of the functions provided. * * These are main 'external' functions that would be used normally. * They revolve round a field structure that defines the field type, its * position on the screen, the attribute used for displaying the field, * keeps some internal information about where in the field the * cursor is etc. * * newfield(t,att,x,y,w,dp,id,dp) create a new SCField structure and init. it * actfield(k,SCFp) action key on field defined by SCField *SCFp * putfield(SCFp) display field defined by SCField *SCFp * * * For definitions of SCField etc see scfio.h * * These functions can be considered 'internal' but can be used by the * brave :-) ..... * * actfstr(k,att,s,ip,w) action key on a string on screen - w max characters * putfstr(att,s,w) display a string on screen - w max characters * actfrac(k,att,ip,w,o,dp) action key on a fraction on screen - w max chars, dp dec places * putfrac(att,i,w,dp) display a fraction on screen - w max chars, dp dec places * actfopt(k,att,sp,ip,w) action key on one of options char *sp[] set *ip to selected * putfopt(att,sp,i,w) display char *sp[i] in field of width w * * Remember an integer is a decimal fraction with 0 decimal points, * therefore for integers use.... * * actfrac(k,att,ip,w,o,0) and putfrac(att,i,w,0) */ #include #include #include #include #include #include #include #include "scfio.h" /* local header file */ /* reverse_attr(a) calculate the reverse attribute of attribute 'a' * if its not a color pair then simply toggle A_REVERSE on 'a' * if it is a color pair then make it COLOR_PAIRS-pair_number */ reverse_attr(a) int a; { int r; if (PAIR_NUMBER(a)) r=(a&(~A_COLOR))+(COLOR_PAIR(COLOR_PAIRS-PAIR_NUMBER(a))); else r=((a+A_REVERSE)&A_REVERSE)+(a&~A_REVERSE); return(r); } /* Fixed Point Fractions. * * The fixed point fraction support defines the fraction as * an integer value plus the number of decimal places required. * Hence 2.34 would be stored as the integer 234 with DP of 2 * * An Integer I, and decimal places of d defines the number I * 10^-d * * OK its tacky and awkward, but I just don't like real numbers, and * this way you can deal with money values easily (e.g. all values can be * integer pence but displayed as pounds with a DP of 2) and alot of other * things. */ /* actfrac(k,att,ip,w,o,DP) action key k on fixed fractional field of * width w, attribute att, number of decimal points DP * cursor is *o chars back from end of display string * digits build up integer value, pushing digits at cursor leftwards * DEL or backspace erases digit above cursor, * moving digits in from left, * KEY_UP (or +) / KEY_DOWN (or -) inc's/dec's the integer * by 1 at the digit above the cursor, with carry/borrow to left. * KEY_LEFT / KEY_RIGHT move cursor thru' the number. * ip points to where to store the integer. */ actfrac(k,att,ip,w,o,DP) int k,att,*ip,w,*o,DP; { int c,N,P,y,x; getyx(stdscr,y,x); w=RANGE(0,w,COLS-x); *o=RANGE(0,*o,MAXINTWIDTH-1); P=POWERS10[(DP)?((*o>DP)?*o-1:*o):*o]; c=-1; N=*ip; if (k=='\b' || k==KEY_BACKSPACE || k==127 || k==KEY_DC) { N=(N/(P*10))*P+N%P; } else if (isascii(k) && isdigit(k)) { N=(((N/P)*10+k-'0')*P) + N%P ; } else if (k==KEY_UP || k=='+') { N+=P; } else if ((k==KEY_DOWN || k=='-') && *ip/P) { N-=P; #ifdef CLOSED_FIELDS } else if (k==KEY_LEFT) { if (*o<(w-1) && (*o<(MAXINTWIDTH-1))) { (*o)++; if (DP && *o==DP) *o+=(*o==(w-1))?-1:1; } } else if (k==KEY_RIGHT) { if (*o) { (*o)--; if (DP && *o==DP) (*o)--; } #else } else if ((k==KEY_LEFT) && (*o<(w-1)) && (*o<(MAXINTWIDTH-1))) { (*o)++; if (DP && *o==DP) *o+=(*o==(w-1))?-1:1; } else if ((k==KEY_RIGHT) && *o) { (*o)--; if (DP && *o==DP) (*o)--; #endif } else { c=k; } if (c==-1) { *ip=( N>(LIMITS(RANGE(0,((DP>0)?w-1:w),MAXINTWIDTH))) ) ? *ip : N; putfrac(att,*ip,w,DP); } move(y,x+w-1-*o); refresh(); return(c); } /* putfrac(att,n,w,DP) display fixed decimal n in a field * of width w, with DP decimal places, using attribute att. * assumes correctly positioned at start of field. */ putfrac(att,n,w,DP) int att,n,w,DP; { int c,i,j,wd,x,y; chtype f[MAXCOL]; w=RANGE(0,w,COLS-1); if (DP>0 && w>DP) wd=w-DP; else wd=w+1; for (c='0', i=w, j=n; i; i--) { if (i==wd) { f[i]=att+'.'; continue; } f[i]=j%10+att+c; j/=10; if (!j && i=w) *op=w-1; if (*op<0) *op=0; if (k=='\b' || k==KEY_BACKSPACE || k==127) { if (*op) { for ( q=s+(--(*op)) ; *q=*(q+1); q++) { } *q=' '; } } else if (isascii(k) && isprint(k)) { for ( q=s+*op ; *q; q++) { l=*q; *q=k; k=l; } if (*op<(w-1)) (*op)++; } else if (k==KEY_DC) { for ( q=s+*op ; *q=*(q+1); q++) { } *q=' '; #ifdef CLOSED_FIELDS } else if (k==KEY_LEFT) { if (*op) (*op)--; } else if (k==KEY_RIGHT) { if (*op<(w-1)) (*op)++; #else /* open fields */ } else if (k==KEY_LEFT && *op) { (*op)--; } else if (k==KEY_RIGHT && (*op<(w-1))) { (*op)++; #endif } else if (k==KEY_HOME) { *op=0; } else if (k==KEY_END) { *op=w-1; } else { move(y,x+*op); return(k); } s[w]=0; mvputfstr(y,x,att,s,w); move(y,x+*op); refresh(); return(-1); } /* putfstr(att,s,o,w) display string s in a field * of width w using attribute att. */ putfstr(att,s,w) int att; char *s; int w; { int c,i,x,y; chtype f[MAXCOL],*p; if (w>=COLS) w=COLS-1; for ( p=f, i=0 ; i=COLS-x) w=COLS-x; if (k=='\b' || k==KEY_BACKSPACE || k==127 || k==KEY_UP) { k=KEY_UP; if (*ip) (*ip)--; else k=KEY_END; } /* no else here on purpose */ if (k==KEY_DOWN || k==' ') { (*ip)++; if (sp[*ip]==NULL) *ip=0; } else if (k==KEY_HOME) { *ip=0; } else if (k==KEY_END) { for ( ; sp[*ip+1]!=NULL; (*ip)++) { } } else if (k!=KEY_UP) { return(k); } putfstr(att,sp[*ip],w); refresh(); return(-1); } /* newfield(t,att,x,y,w,dp,id,dp) create a SCField structure and fill it in * if any problems return NULL else return ptr to structure. */ struct SCField *newfield(t,att,x,y,w,d,id,dp) int t,att,x,y,w; void *d; int id,dp; { struct SCField *sp; int ft,n; ft=t&SCF_type; if (ft==SCF_integer) { /* if (RANGE(0,w,MAXINTWIDTH)!=w) return(NULL); */ n=sizeof(struct SCField) + ((d==NULL)?sizeof(int):0); if ((sp=(struct SCField *)malloc(n))==NULL) return(NULL); if (d==NULL) d=(int *)(sp+sizeof(struct SCField)); sp->val.i=(int *)d; } else if (ft==SCF_string) { n=sizeof(struct SCField) + ((d==NULL)?w+2:0); if ((sp=(struct SCField *)malloc(n))==NULL) return(NULL); if (d==NULL) d=(int *)(sp+sizeof(struct SCField)); sp->val.s=(char *)d; } else if (ft==SCF_option) { if (d==NULL) return(NULL); if ((sp=(struct SCField *)malloc(sizeof(struct SCField)))==NULL) return(NULL); sp->val.sp=(char **)d; } else return(NULL); sp->type=t; sp->attr=att; sp->row=y; sp->col=x; sp->W=w; sp->id=id; sp->adj=0; sp->dp=dp; return(sp); } /* putfield(fp) display field *fp */ putfield(fp) struct SCField *fp; { int t; t=(fp->type)&SCF_type; if (t==SCF_integer) { mvputfrac(fp->row,fp->col,fp->attr,*(fp->val.i),fp->W,fp->dp); t=(fp->W)-(fp->adj)-1; } else if (t==SCF_string) { mvputfstr(fp->row,fp->col,fp->attr,fp->val.s,fp->W); t=(fp->adj); } else if (t==SCF_option) { mvputfstr(fp->row,fp->col,fp->attr,(fp->val.sp)[fp->adj],fp->W); t=(fp->W)-1; } else return(1); setsyx(fp->row,(fp->col)+t); return(0); } /* dupfield(fp) duplicate field *fp */ struct SCField *dupfield(fp) struct SCField *fp; { struct SCField *p; p=(struct SCField *)malloc(sizeof(struct SCField)); if (p==NULL) return(NULL); return( (struct SCField *)memcpy(p,fp,sizeof(struct SCField)) ); } /* actfield(k,fp) action key k on field *fp */ actfield(k,fp) int k; struct SCField *fp; { int t,c; if ((fp->type)&SCF_fixed) return(k); t=(fp->type)&SCF_type; if (t==SCF_integer) c=mvactfrac(fp->row,fp->col,k,fp->attr,fp->val.i,fp->W,&(fp->adj),fp->dp); else if (t==SCF_string) c=mvactfstr(fp->row,fp->col,k,fp->attr,fp->val.s,&(fp->adj),fp->W); else if (t==SCF_option) c=mvactfopt(fp->row,fp->col,k,fp->attr,fp->val.sp,&(fp->adj),fp->W); else return(-1); return(c); } siggen-2.3.10/config.h.linux0000600000175000017500000001636510404120761014271 0ustar jjfamily/* config.h * global config header file for all programs * Jim Jackson */ /* * Copyright (C) 2000 Jim Jackson jj@franjam.org.uk */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #ifndef _config_siggen_h #define _config_siggen_h /* USER CONFIGUARABLE STUFF ------------------------------- */ /* * NO_DAC_DEVICE uncomment/set this to build sgen, swgen or tones * in wav/raw data file output mode only. * This turns off all reference to soundcards and * DSP/Audio devices. */ /*#define NO_DAC_DEVICE*/ /* SUNOS uncomment/set this for compiling under SUNOS 4 */ /*#define SUNOS*/ /* --------------------------------------------- * These options are dynamically configurable via the runtime config * files. The values below define default values. * * Non-string configurable options should have a Qxxxxx definition * to define the string equivalent of the value. */ /* DEF_CONF_FILENAME name of local runtime config file. */ #define DEF_CONF_FILENAME ".sound.conf" /* DEF_GLOBAL_CONF_FILE name of default global configuration file. * The startup process looks for a config file in local directory, * then home directory, and finally looks for this file. * For structure of config files see sample .sound.conf */ #define DEF_GLOBAL_CONF_FILE "/etc/sound.conf" /* DAC_FILE is name of sound output device */ #define DAC_FILE "/dev/dsp" /* MIXER_FILE is name of mixer device */ #define MIXER_FILE "/dev/mixer" /* DEF_PLAYTIME is default playing time for file output in millisecs */ #define DEF_PLAYTIME 1000 #define QDEF_PLAYTIME "1000" /* SAMPLERATE is default samplerate to use, could be 8000 for simple * stuff or 44100 for HiFi quality. */ #define SAMPLERATE 22050 #define QSAMPLERATE "22050" /* VI_KEYS set to 1 if the VI cursor moving keys "HJKL" are to be active. */ #define VI_KEYS 0 #define QVI_KEYS "0" /* DEF_TONES_CHANNELS default number of channels for tones program */ #define DEF_TONES_CHANNELS 4 #define QDEF_TONES_CHANNELS "4" /* DEF_FSYNTH_CHANNELS default number of channels for fsynth program */ #define DEF_FSYNTH_CHANNELS 13 #define QDEF_FSYNTH_CHANNELS "13" /* DEFAULT_FRAGMENTS number of buffer fragments to configure in sound driver * for playing. Used by interactive programs to limit * the 'play ahead' of sound samples so that parameter changes * appear to happen 'straight' away. This is a compromise * too few buffers and there may not be enough play ahead * to cover the time that other programs are running, * too many buffers and the programs feel very unresponsive. * The programs attempt to set the buffer size dependant on * the samplerate, so that one buffer takes very approx. * 100millisecs of samples (buffer size is the nearest * power of 2). */ #define DEFAULT_FRAGMENTS 3 #define QDEFAULT_FRAGMENTS "3" /* DEFAULT_BUFFSPERSEC number of buffers to play per second - aproximately * This is used to calculate the buffer fragment size, depending on this * samplerate, stereo/mono, 16 or 8 bit samples. Buffer size is always * a power of 2 anyway. */ #define DEFAULT_BUFFSPERSEC 15 #define QDEFAULT_BUFFSPERSEC "15" /* DEF_WN default number of loadable waveforms to allow */ #define DEF_WN 10 #define QDEF_WN "10" /* these config params are hard coded here..... * * LOCK_FIELD_CHARS is the string of characters that are recognised * for locking/freezing values in a field in curses progs * by default "!lL" but if vikeys is used "lL" will not be * available 'cos it equates KEY_LEFT * UNLOCK_FIELD_CHARS ditto for chars to cause unlocking of all fields */ #define LOCK_FIELD_CHARS "!lL" #define UNLOCK_FIELD_CHARS "uU" /* Color configuration. 6 color combinations are used. * Each consists of Foreground and Background colors. * If the color pair are used for input fields then the fore and back * ground colors are reversed when that field is being input/altered. * * ColorPair1 for main header and footer * ColorPair2 for the "ASCII ART" header banner * ColorPair3 for the author sig field, the 2 "help" lines at bottom of * screen, and the clock and labels on the digital audio * details line under main header. * ColorPair4 Digital Audio sample value fields - samplerate, * bits, mono/stereo, buffers etc * ColorPair5 Main central screen fixed layout * ColorPair6 Input value fields in main central screen */ #define ColorPair1 Define_Color(1,COLOR_BLUE,COLOR_GREEN) #define ColorPair2 Define_Color(2,COLOR_YELLOW,COLOR_BLUE) #define ColorPair3 Define_Color(3,COLOR_GREEN,COLOR_RED) #define ColorPair4 Define_Color(4,COLOR_CYAN,COLOR_RED) #define ColorPair5 Define_Color(5,COLOR_WHITE,COLOR_BLUE) #define ColorPair6 Define_Color(6,COLOR_RED,COLOR_CYAN) /* End of USER CONFIGURABLE STUFF ------------------------- */ /* Some color setting macros...... */ #define Define_Color(C,F,B) { init_pair(C,F,B) ; \ init_pair(COLOR_PAIRS-C,B,F); } #ifndef ColorPair1 # define ColorPair1 Define_Color(1,COLOR_BLUE,COLOR_GREEN) #endif #ifndef ColorPair2 # define ColorPair2 Define_Color(2,COLOR_YELLOW,COLOR_BLUE) #endif #ifndef ColorPair3 # define ColorPair3 Define_Color(3,COLOR_GREEN,COLOR_RED) #endif #ifndef ColorPair4 # define ColorPair4 Define_Color(4,COLOR_CYAN,COLOR_RED) #endif #ifndef ColorPair5 # define ColorPair5 Define_Color(5,COLOR_WHITE,COLOR_BLUE) #endif #ifndef ColorPair6 # define ColorPair6 Define_Color(6,COLOR_RED,COLOR_CYAN) #endif /* Set various things depending on what the user configures..... * * If no soundcard stuff, we need to define the AFMT values. * If SUNOS we need to do some extern stuff, and include the correct * string(s).h */ #ifndef NO_DAC_DEVICE #define HAVE_DAC_DEVICE #include #else #define AFMT_QUERY 0 #define AFMT_S16_LE 16 #define AFMT_U8 8 #endif #define QAFMT_QUERY "0" #ifdef SUNOS extern char *sys_errlist[]; extern int sys_nerr; extern char *strrchr(),*strlchr(); #define BIGENDIAN #endif #define EFAIL -1 /* Some useful defines that are common to all programs...... */ /* define the dB function for converting a dB * value to a linear amplitude factor. Assumes and returns double values */ #define dB(X) pow(10,X/20.0) /* and some predefinitions...... */ char *get_conf_value(); #endif /* _config_siggen_h */ siggen-2.3.10/sgen.c0000600000175000017500000003763311011656525012625 0ustar jjfamily/* sgen.c * makes a raw 8 or 16 bit digital sound signal of a waveform of a particular * frequency and sampling rate. Output is to a file, or /dev/dsp (linux) * Jim Jackson Linux Version */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* History................... * * Based on my noddy DOS version which created sample files to be played * by other utils. This had lotsa faults, now fixed. * * 09Mar03 Bug fixed in calculating playsamples for long periods * 3Jun99 Some tidying up of WAV file writing * 1Sep98 added configuration file(s) support * 18Jun98 added the x10 feature where frequencies are specified * as integers 10 times too big, so that freqs with a resolution * of 0.1 Hz can be generated. * 18Jun98 added the define NO_DAC_DEVICE * if true it compiles to a raw/wav file creator only. * 04Aug97 Added -t option to specify time to play * 18Mar97 -f flag was missing - added it back. * Added default sine waveform if none specified on line. * 15Mar97 Bug in initialising second channel to silence - it re-init first * channel again. Reported by Michael Meifert * 10Feb97 Added -w option to write out samples as a wave file * --- for signal generation notes etc see generator.c * 29Dec96 Added amplitude factor -A N where N is a percentage. * The sample is created to optimally fill the sample space when * N is 100 (the default value). The samples generated are scaled * by N/100, overly large values simply being 'clipped'. * To create a trapezoid wave form, generate a triangle wave * with N>100, depending on slope needed on waveform. * 18Dec96 Started splitting up stuff into different files so that I can * write some different front ends. All the code to create the * samples is in generator.c, and some misc. stuff in misc.c * --Dec96 Added noise generator using the random function - sounds ok * Need to figure what to do to get pink noise - I think! * --Oct96 Original Linux version. Fixed faulty sample generation * in DOS program - you have to generate samples over several * cycles to ensure that a you can put samples end-to-end * to fill a second, see comments in mksin(). Added stereo * and antiphase stuff. Eventually worked out how to generate * square/pulse signals accurately, and sawtooth. * Triangle still to do. */ /* In mono only one buffer is used to hold one secs worth of samples * because we only allow integers to specify the frequency, we always * have an exact number of full cycles in one sec, therefore this buffer * can be treated cyclically to generate the signal for any period. * * In stereo, two buffers hold the signal for each channel - 2nd channel is * either an in phase or antiphase copy of channel 1 at moment - and they * are mixed into a large double size playing buffer. */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #define VERSTR "%s Ver. %s Digital Signal Generator\n" #define EFAIL -1 #define MAXPRM 32 #define chkword(a,b) ((n>=a)&&(strncmp(p,b,n)==0)) int aflg,fflg,vflg,dflg,wfmt; unsigned int samplerate,freq; /* Samples/sec and signal frequency */ unsigned int freqX; /* generate samples at samplerate*freqX */ unsigned int ratio; /* used in pulse, sweep etc */ unsigned int antiphase; /* 2nd channel in antiphase to 1st channel */ unsigned int Gain; /* Amplification factor */ int stereo; /* stereo mono */ unsigned int afmt; /* format for DAC */ unsigned int frag_size; /* size of DAC buffer fragments */ int lbuf_flag,rbuf_flag; unsigned char *lbuf,*rbuf; /* waveform bufs, left and right channels */ unsigned int lbuf_size; /* size of 1 sec, 1 chan, waveform buffer */ unsigned char *plbuf; /* play buffer - mixed left and right bufs */ unsigned char *silbuf; /* silence buffer - used for timed output */ int plbuf_size; /* size of playback buffer */ long playtime,playsamples; /* number of millisecs/samples to play 0 means play for ever */ char *sys,*outfile; char dac[130]; char *configfile; help(e) int e; { char **aa; fprintf(stderr,VERSTR,sys,VERSION); fputs("\nUsage: \n 1: sgen [flags] waveform freq\n",stderr); fputs(" waveform is",stderr); for ( aa=(char **)getWavNames(); *aa; aa++ ) fprintf(stderr," %s",*aa); fputs("\n",stderr); fputs(" 2: sgen [flags] sin|cos freq [phase]\n",stderr); fputs(" sin/cos has extra phase param (def. is 0 degrees)\n",stderr); fputs(" 3: sgen [flags] pulse freq [Mark/Space]\n",stderr); fputs(" pulse has extra param Mark/Space % - def. is 10 (%)\n",stderr); #ifdef HAVE_DAC_DEVICE fprintf(stderr,"Defaults: output continuously to %s, %d samples/sec, mono,\n", DAC_FILE,SAMPLERATE); fputs(" 16 bit samples if possible, else 8 bit.\n",stderr); #else fputs("An output file MUST be specified with either the -o or -w option.\n",stderr); fprintf(stderr,"Defaults: 1 second's worth of %d samples/sec, mono, 16 bit samples.\n",SAMPLERATE); #endif fprintf(stderr,"Default Config files are \"%s\", \"$(HOME)/%s\" and\n\"%s\", searched in that order.\n", DEF_CONF_FILENAME, DEF_CONF_FILENAME, DEF_GLOBAL_CONF_FILE); fputs("flags: -f,-a force overwrite/append of/to file\n",stderr); fputs(" -o file write digital sample to file ('-' is stdout)\n",stderr); fputs(" -w file as '-o' but written as a wave file\n",stderr); fputs(" -C file use file as local configuration file\n",stderr); fputs(" -s samples generate with samplerate of samples/sec\n",stderr); fputs(" -v be verbose.\n",stderr); fputs(" -8/-16 or -b 8|16 force 8 bit or 16 bit mode.\n",stderr); fputs(" -1,-2a mono (def) or stereo in antiphase\n",stderr); fputs(" -A n scale samples by n/100, def. n is 100\n",stderr); fputs(" -t N|Nm play for N secs or Nm millisecs\n",stderr); fputs(" -x10|-x100 scale freqs down by factor of 10/100\n",stderr); fputs(" allows freqs to 0.1/0.01 of a hertz.\n",stderr); return(e); } /* main * */ main(argc,argv) int argc; char **argv; { unsigned int v[MAXPRM],maxv,i,j,k,l,m,n,N; FILE *f; char *p,*wf,*fnm,fname[130],*omode; int fd,st; unsigned int t; if ((p=strrchr(sys=*argv++,'/'))!=NULL) sys=++p; argc--; configfile=DEF_CONF_FILENAME; outfile=NULL; samplerate=0; afmt=AFMT_QUERY; stereo=-1; antiphase=wfmt=0; Gain=100; playtime=playsamples=dflg=vflg=aflg=fflg=0; freqX=1; while (argc && **argv=='-') { /* all flags and options must come */ n=strlen(p=(*argv++)+1); argc--; /* before paramters */ if (chkword(1,"samplerate")) { if (argc && isdigit(**argv)) { samplerate=atoi(*argv++); argc--; } } else if (chkword(4,"x100")) { freqX=100; } else if (chkword(3,"x10")) { freqX=10; } else if (chkword(1,"output")) { /* e.g. string option */ if (argc) { outfile=*argv++; argc--; } /* output file name */ } else if (chkword(1,"w")) { /* e.g. string option */ if (argc) { outfile=*argv++; argc--; wfmt=1; } /* output file name */ } else if (chkword(2,"16")) { afmt=AFMT_S16_LE; } else if (chkword(1,"bits")) { i=0; if (argc) { i=atoi(*argv++); argc--; } if (i==8) afmt=AFMT_U8; else if (i==16) afmt=AFMT_S16_LE; else exit(err_rpt(EINVAL,"must be '-b 8' or '-b 16'.")); } else if (chkword(1,"time")) { i=0; if (argc) { i=strtol(*argv++,&p,10); argc--; if (*p=='s' || *p==0) i*=1000; /* time specified in secs - *1000 for ms */ else if (*p!='m') exit(err_rpt(EINVAL,"Invalid time specification.")); } playtime=i; } else if (chkword(1,"A")) { if (argc && isdigit(**argv)) { Gain=atoi(*argv++); argc--; } } else if (chkword(2,"2a")) { stereo=antiphase=1; } else if (chkword(1,"Config")) { if (argc && **argv != '-') { configfile=*argv++; argc--; } } else { /* check for single char. flags */ for (; *p; p++) { if (*p=='h') exit(help(EFAIL)); else if (*p=='1') stereo=0; else if (*p=='2') stereo=1; else if (*p=='8') afmt=AFMT_U8; else if (*p=='a') aflg=1; else if (*p=='f') fflg=1; else if (*p=='d') dflg=1; else if (*p=='v') vflg++; else { *fname='-'; *(fname+1)=*p; *(fname+2)=0; exit(help(err_rpt(EINVAL,fname))); } } } } /* interrogate config file....... */ init_conf_files(configfile,DEF_CONF_FILENAME,DEF_GLOBAL_CONF_FILE,vflg); if (vflg==0) { vflg=atoi(get_conf_value(sys,"verbose","0")); } if (samplerate==0) { samplerate=atoi(get_conf_value(sys,"samplerate",QSAMPLERATE)); } if (stereo==-1) { stereo=atoi(get_conf_value(sys,"channels","1")); if (stereo) stereo--; } if (afmt==AFMT_QUERY) { afmt=atoi(get_conf_value(sys,"samplesize",QAFMT_QUERY)); } strncpy(dac,get_conf_value(sys,"dacfile",DAC_FILE),sizeof(dac)-1); /* check signal params ......... */ if (argc==0) exit(help(err_rpt(EINVAL,"Wrong number of parameters."))); wf="sine"; if (!isdigit(**argv)) { wf=*argv++; argc--; /* waveform type */ } if (argc) { freq=atoi(*argv++); argc--; ratio=-1; if (argc) { ratio=atoi(*argv++); argc--; } } if (argc) exit(help(err_rpt(EINVAL,"Wrong number of parameters."))); /* open the right device or output file............ */ if (vflg) printf(VERSTR,sys,VERSION); if (outfile==NULL) { #ifdef HAVE_DAC_DEVICE /* if no outfile then write direct to DAC */ /* if no format specified then try 16 bit */ i=(afmt==AFMT_QUERY)?AFMT_S16_LE:afmt ; n=stereo; if ((fd=DACopen(fnm=dac,"w",&samplerate,&i,&n))<0) { if (afmt==AFMT_QUERY) { /* if no format specified try for 8 bit.. */ i=AFMT_U8; fd=DACopen(fnm,"w",&samplerate,&i,&n); } if (fd<0) exit(err_rpt(errno,fnm)); } if ((frag_size=getfragsize(fd))<0) exit(err_rpt(errno,"Problem getting DAC Buffer size.")); afmt=i; if (vflg) { printf("%s : DAC Opened for output\n",fnm); printf("%d %s, %s, samples/sec.\n",samplerate, (stereo)?"stereo":"mono", (i==AFMT_U8)?"unsigned 8 bit": ((i==AFMT_S16_LE)?"signed 16 bit, little endian": "Unknown audio format")); printf("%d bytes per DAC buffer.\n",frag_size); } if (i!=afmt || n!=stereo) { exit(err_rpt(EINVAL,"Sound card doesn't support format requested.")); } #else /* error if no outfile specified */ exit(help(err_rpt(EINVAL,"No output file specified, use -w or -o option."))); #endif } else { /* outfile!=NULL so writing to a file */ if (aflg && wfmt) { exit(err_rpt(EINVAL,"Cannot write append to a WAVE file.")); } afmt=(afmt==AFMT_QUERY)?AFMT_S16_LE:afmt ; /* set 16 bit mode unless * some format is forced */ omode=(aflg)?"a":"w"; if ((f=fopen(fnm=outfile,"r"))!=NULL) { fclose(f); if ( (!aflg) && (!fflg) ) exit(err_rpt(EEXIST,fnm)); } if ((f=fopen(fnm,omode))==NULL) { exit(err_rpt(errno,fnm)); } if (vflg) { fputs(fnm,stdout); if (*omode=='a') fputs(": Opened in append mode.\n",stdout); else fputs(": Opened clean for writing.\n",stdout); } fd=fileno(f); if (playtime==0) playtime=DEF_PLAYTIME; } /* calc number of samples to play */ if (playtime) { if ((playsamples=mstosamples(playtime,samplerate))==0) exit(err_rpt(EINVAL,"Arithmetic overflow when calculating number of samples.")); } lbuf_size=samplerate*freqX; /* buf sizes if 8 bit samples */ if (afmt==AFMT_S16_LE) lbuf_size<<=1; /* double size if 16 bit */ else if (afmt!=AFMT_U8) { exit(err_rpt(EINVAL,"Only unsigned 8 and signed 16 bit, supported.")); } lbuf_flag=rbuf_flag=0; lbuf=(unsigned char *)malloc(lbuf_size); rbuf=(unsigned char *)malloc(lbuf_size); plbuf=(unsigned char *)malloc(plbuf_size=lbuf_size<1) printf("All frequency values to be divided down by %d\n",freqX); printf("%d Hz, %s bit %s samples being generated.\n", freq,(afmt==AFMT_S16_LE)?"16":"8",(stereo)?"Stereo":"Mono"); if (playtime) { printf("Playing for %d.%03d millisecs, %d samples.\n", playtime/1000,playtime%1000,playsamples); } printf("Samples scaled by a factor of %d/100.\n",Gain); printf("%d byte buffer allocated per channel.\n",lbuf_size); } if ((freq==0) || (freq >= samplerate*freqX/2)) { fprintf(stderr,"Frequency (%dHz) should less than half the sampling rate and not zero.\n",freq); exit(err_rpt(EINVAL,"Frequency setting")); } if (generate(wf,lbuf,lbuf_size,freq,Gain,samplerate*freqX,ratio,afmt)==0) { exit(err_rpt(ENOSYS,wf)); } if (stereo) { if (antiphase) { do_antiphase(rbuf,lbuf,samplerate*freqX,afmt); } else memcpy(rbuf,lbuf,lbuf_size); mixplaybuf(plbuf,lbuf,rbuf,samplerate*freqX,afmt); } else { memcpy(plbuf,lbuf,plbuf_size); } if (outfile==NULL) { /* writing to audio device.... */ if (playtime) { n=(playsamples< 100%. In fact a trapezoid signal can be made by generating a clipped sawtooth wave. The greater the gain, the closer the signal approaches a square wave (the rise and fall times decrease). .PP .I siggen generates one seconds worth of 1 Hz samples at the specified samplerate, for each waveform, and generates frequency F by circularly sampling every Fth sample. Each buffer fragment is generated for the parameter(s) set at that moment. Buffer fragment sizes are set so that aprox. 10 fragments/sec are generated. Changing a generation parameter, e.g. waveform, frequency, gain, will impact the next buffer fragment generated, and hence changes appear to be almost immediate. .PP If your sounds periodically 'breaks' up with clicks or breaks, it is usually a sign that siggen is not being scheduled sufficiently often. Either up the priority (see .I nice et al.), kill off other processes, get a faster processor, or increase the number of audio buffer fragments that siggen uses. This last will make siggen respond more sluggishly to changes in generation parameters. .I syslogd and .I crond are two processes that I've found useful to kill off - YMMV. .IP Defaults output to /dev/dsp, 22050 samples/sec, stereo if stereo card else mono, 16 bit samples if possible, else 8 bit, 3 audio buffer fragments. .SH OPTIONS .IP -h display usage and help info .IP -v be verbose .IP -s\ samples generate with samplerate of samples/sec .IP -8|-16\ or\ -b\ 8|16 force 8 bit or 16 bit mode. .IP -1|-2 mono or stereo .SH EXAMPLES .SH .SH FILES .SH .SH SEE ALSO sgen, swgen, tones, sweepgen .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/config.h.sunos0000600000175000017500000000676310404121016014274 0ustar jjfamily/* config.h * global config header file for all programs * Jim Jackson Jun 98 */ #ifndef _config_siggen_h #define _config_siggen_h /* USER CONFIGUARABLE STUFF ------------------------------- */ /* * NO_DAC_DEVICE uncomment/set this to build sgen, swgen or tones * in wav/raw data file output mode only. * This turns off all reference to soundcards and * DSP/Audio devices. * * SUNOS uncomment/set this for compiling under SUNOS 4 */ #define NO_DAC_DEVICE #define SUNOS /* DAC_FILE is name of sound output device * DEF_PLAYTIME is default playing time for file output in millisecs * SAMPLERATE is default samplerate to use, could be 8000 for simple * stuff or 44100 for HiFi quality. * VI_KEYS true if the VI cursor moving keys "HJKL" are to be active. * DEF_TONES_CHANNELS default number of channels for tones program * DEF_FSYNTH_CHANNELS default number of channels for fsynth program * DEF_CONF_FILENAME name of local config file. * DEF_GLOBAL_CONF_FILE name of default global configuration file. * The startup process looks for a config. file in local directory, * then home directory, and finally looks for this file. * For structure of config files see sample .sound.conf * DEFAULT_FRAGMENTS number of buffer fragments to configure in sound driver * for playing. Used by interactive programs to limit * the 'play ahead' of sound samples so that parameter changes * appear to happen 'straight' away. This is a compromise * too few buffers and there may not be enough play ahead * to cover the time that other programs are running, * too many buffers and the programs feel very unresponsive. * The programs attempt to set the buffer size dependant on * the samplerate, so that one buffer takes very approx. * 100millisecs of samples (buffer size is the nearest * power of 2). * DEF_WN default number of loadable waveforms to allow */ #define DAC_FILE "/dev/dsp" #define DEF_PLAYTIME 1000 #define QDEF_PLAYTIME "1000" #define SAMPLERATE 22050 #define QSAMPLERATE "22050" #define VI_KEYS 0 #define QVI_KEYS "0" #define DEF_TONES_CHANNELS 4 #define QDEF_TONES_CHANNELS "4" #define DEF_FSYNTH_CHANNELS 13 #define QDEF_FSYNTH_CHANNELS "13" #define DEF_WN 10 #define QDEF_WN "10" #define DEF_CONF_FILENAME ".sound.conf" #define DEF_GLOBAL_CONF_FILE "/etc/sound.conf" #define DEFAULT_FRAGMENTS 3 #define QDEFAULT_FRAGMENTS "3" /* End of USER CONFIGURABLE STUFF ------------------------- */ /* Set various things depending on what the user configures..... * * If no soundcard stuff, we need to define the AFMT values. * If SUNOS we need to do some extern stuff, and include the correct * string(s).h */ #ifndef NO_DAC_DEVICE #define HAVE_DAC_DEVICE #include #else #define AFMT_QUERY 0 #define AFMT_S16_LE 16 #define AFMT_U8 8 #endif #define QAFMT_QUERY "0" #ifdef SUNOS extern char *sys_errlist[]; extern int sys_nerr; extern char *strrchr(),*strlchr(); #define BIGENDIAN #endif #define EFAIL -1 /* Some useful defines that are common to all programs...... */ /* define the dB function for converting a dB * value to a linear amplitude factor. Assumes and returns double values */ #define dB(X) pow(10,X/20.0) /* and some predefinitions...... */ char *get_conf_value(); #endif /* _config_siggen_h */ siggen-2.3.10/README.tones0000600000175000017500000001120110404121305013477 0ustar jjfamily Some notes on the 'tones' program. Jim Jackson ---------------------------------- May 1999 The tones program has growed out of a simple sequential tone generator that I wrote for Michael Meifert for generating a sequence of tones for control purposes. Since then I've expanded it to maintain a set of 'channels', each channel having a seperately configured waveform, frequency and intensities. All the channels are mixed to provide the output signal. Mark E. Shoulson provided a base patch for adding intensity levels. However this showed up bugs in the digital mixer which have now been fixed and the amplitude handling much expanded - see the relevant sections in the manual page. Musical note generation Also I've added the ability to generate musical notes, by being able to specify a note + optional sharp + octave digit, e.g. C3 is middle C. The tuning is based on the standard concert A of 440Hz (A3), and an equally tempered scale. Thanks to Ivor Dykes for the music lessons! If you want a different tuning then the frequencies are defined in an array in tonesgen.c, and can easily be altered to taste. Thanks also to Robert P. Hanssen for pointing out a correction to the freq. numbers used for generating named notes. Some examples tones 2000 sin c3,e3,g3 plays the C Major chord tones 100 sin 941,1336 0,0 697,1209 0,0 697,1209 0,0 697,1477 0,0 generate the dtmf dial tones for '0' '1' '1' '3' Here are the frequencies to use..... 1 = 697,1209 2 = 697,1336 3 = 697,1477 4 = 770,1209 5 = 770,1336 6 = 770,1477 7 = 852,1209 8 = 852,1336 9 = 852,1477 0 = 941,1336 * = 941,1209 # = 941,1477 tones -loop :2000 sin 1000 square 1000 tri 1000 saw 1000 0 generate a series of test waveforms repeatedly. The ':' infront of the default duration setting forces this to be a duration setting even on the loop - otherwise it would be treated as a freq. spec. Yeah it's a bug - but I couldn't see an easy fix. More examples in the tones.eg directory In sub-directory, tones.eg, there are some examples using the tones program. Run make in the tones.eg directory to create the programs ramp, randtone, randnote and shepard-risset, and create some more complex loadable waveforms in the tones.eg/samples directory. Then try the shell scripts ramp.sh, randtone.sh, randnote.sh, slide.sh (the shepard-risset sliding scale) and tune.sh . ramp.sh generate a slow ramp modulated frequency. Edit the script to change the parameters. 'ramp' simple generates a suitable series of incrementing (or decrementing) numbers that tones converts into successive short tones. randtone.sh generates random tones of varying duration. randnote.sh generates random notes slide.sh creates and plays a sample shepard-risset sliding scale tt.sh plays "There's a hole in my bucket" using the loadable waveform given as a parameter to the script. tune.sh plays a couple of tunes! File hole_bucket.notes contains the notes for a simple tune. clementine.notes contains the notesi for a more complex tune with harmony (clementine). Just for fun. dtmf script to create dtmf dial tones for single digits given as parameters to the script. e.g. dtmf 0 1 1 3 6 6 6 shepard-risset is a C program to generate tones commands for generating Shepard-Risset sliding tones - often called elevator sounds because they appear to be moving up (or down) permanently. Try this: % shepard-risset 700 7 1.2 15 -50 > /usr/tmp/slide % tones -c 7 -v -l :200 /usr/tmp/slide or just run the slide.sh script. It uses precomputed sequences for rising and falling elevator sounds. Read the C code or run shepard-risset with no arguments to see what the parameters are. See paper http://www.acm.org/sigchi/chi96/proceedings/shortpap/Beaudoin-Lafon/Mbl_txt.htm for more some more details on shepard-risset tones. Installation of the stuff in tones.eg You can run 'make' in the tones.eg directory and then run the example shell scripts. e.g. % cd tones.eg % make % ./tune.sh If you wish, you can copy the scripts into a suitable directory, your own ~/bin directory or /usr/local/bin. You will have to edit the scripts to put in the location of the tones program - usually /usr/local/bin. The only script worth installing really is 'dtmf' - and I'm sure that can be improved! Feel free - let me know the results. Jim Jackson jj@franjam.org.uk siggen-2.3.10/adB.c0000600000175000017500000000225307076420757012361 0ustar jjfamily/* adB.c * converts gain values given as parameters into dB values * i.e. 1 will give 0dB * 0.5 will give -6dB amplitude / -3dB power * 10 will give 20dB amplitude / 10dB power */ #include #include #include #define db(x) pow(10,x/20.0) #define adb(g) (10*log10(g)) main(argc,argv) int argc; char **argv; { int i,j,k,n; double x,y; char *p; argc--; argv++; for ( ; argc; argc--, argv++) { x=atof(*argv); if ((p=strchr(*argv,'/'))!=NULL) { y=atof(++p); printf("%f/%f = %f = %f dB Ampl. or %f dB power\n", x,y,x/y,2*adb(x/y),adb(x/y)); } else { printf("Ratio of %f = %f dB Ampl. or %f dB power\n", x,2*adb(x),adb(x)); } } } /* double db(x) double x; { return(pow(10,x/20.0); } */ /* db(x) int x; { int i; static int dB_Conv[20]={ 100000000, 112201845, 125892541, 141253754, 158489319, 177827941, 199526231, 223872114, 251188643, 281838293, 316227766, 354813389, 398107171, 446683592, 501187234, 562341325, 630957344, 707945784, 794328235, 891250938 }; for (i=100000000; i && x>=20; x-=20) { i/=10; } return((i)?(dB_Conv[x]/i):-1); } */ siggen-2.3.10/soundinfo.10000644000175000017500000000324611011657044013611 0ustar jjfamily.TH soundinfo 1 "27 Oct 1996" "Release 1" "Linux System Manual" .SH NAME soundinfo \- Describes parts of the Linux Sound system support .SH SYNOPSIS .B soundinfo [options] .SH DESCRIPTION .I soundinfo , describes parts of the Linux Sound system support in the current kernel. Output is to stdout and you may wish to pipe the output thru' your favorite pager. .PP Currently only the capabilities and features of /dev/mixer and /dev/dsp are displayed. If your devices have different names (e.g. you have more than one sound card - or you are just plain perverse :-) then edit the source file and recompile. .SH OPTIONS .IP -h display usage and help info .SH EXAMPLES .SH .SH FILES .SH .SH SEE ALSO .SH .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/config.h0000600000175000017500000001672711011656246013144 0ustar jjfamily/* config.h * global config header file for all programs * Jim Jackson */ /* * Copyright (C) 2000-2008 Jim Jackson jj@franjam.org.uk */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #define VERSION "2.3.10 (May 2008)" #ifndef _config_siggen_h #define _config_siggen_h /* USER CONFIGUARABLE STUFF ------------------------------- */ /* * NO_DAC_DEVICE uncomment/set this to build sgen, swgen or tones * in wav/raw data file output mode only. * This turns off all reference to soundcards and * DSP/Audio devices. */ /*#define NO_DAC_DEVICE*/ /* SUNOS uncomment/set this for compiling under SUNOS 4 */ /*#define SUNOS*/ /* --------------------------------------------- * These options are dynamically configurable via the runtime config * files. The values below define default values. * * Non-string configurable options should have a Qxxxxx definition * to define the string equivalent of the value. */ /* DEF_CONF_FILENAME name of local runtime config file. */ #define DEF_CONF_FILENAME ".siggen.conf" /* DEF_GLOBAL_CONF_FILE name of default global configuration file. * The startup process looks for a config file in local directory, * then home directory, and finally looks for this file. * For structure of config files see sample .siggen.conf */ #define DEF_GLOBAL_CONF_FILE "/etc/siggen.conf" /* DAC_FILE is name of sound output device */ #define DAC_FILE "/dev/dsp" /* MIXER_FILE is name of mixer device */ #define MIXER_FILE "/dev/mixer" /* DEF_PLAYTIME is default playing time for file output in millisecs */ #define DEF_PLAYTIME 1000 #define QDEF_PLAYTIME "1000" /* SAMPLERATE is default samplerate to use, could be 8000 for simple * stuff or 44100 for HiFi quality. */ #define SAMPLERATE 22050 #define QSAMPLERATE "22050" /* RESOLUTION sets the resolution with which some programs generate * signal frequencies. Valid values are 1Hz, 0.1Hz or 0.01Hz */ #define DEFAULT_RESOLUTION "0.1Hz" /* VI_KEYS set to 1 if the VI cursor moving keys "HJKL" are to be active. */ #define VI_KEYS 0 #define QVI_KEYS "0" /* DEF_TONES_CHANNELS default number of channels for tones program */ #define DEF_TONES_CHANNELS 4 #define QDEF_TONES_CHANNELS "4" /* DEF_FSYNTH_CHANNELS default number of channels for fsynth program */ #define DEF_FSYNTH_CHANNELS 13 #define QDEF_FSYNTH_CHANNELS "13" /* DEFAULT_FRAGMENTS number of buffer fragments to configure in sound driver * for playing. Used by interactive programs to limit * the 'play ahead' of sound samples so that parameter changes * appear to happen 'straight' away. This is a compromise * too few buffers and there may not be enough play ahead * to cover the time that other programs are running, * too many buffers and the programs feel very unresponsive. * The programs attempt to set the buffer size dependant on * the samplerate, so that one buffer takes very approx. * 100millisecs of samples (buffer size is the nearest * power of 2). */ #define DEFAULT_FRAGMENTS 3 #define QDEFAULT_FRAGMENTS "3" /* DEFAULT_BUFFSPERSEC number of buffers to play per second - aproximately * This is used to calculate the buffer fragment size, depending on this * samplerate, stereo/mono, 16 or 8 bit samples. Buffer size is always * a power of 2 anyway. */ #define DEFAULT_BUFFSPERSEC 15 #define QDEFAULT_BUFFSPERSEC "15" /* DEF_WN default number of loadable waveforms to allow */ #define DEF_WN 10 #define QDEF_WN "10" /* these config params are hard coded here..... * * LOCK_FIELD_CHARS is the string of characters that are recognised * for locking/freezing values in a field in curses progs * by default "!lL" but if vikeys is used "lL" will not be * available 'cos it equates KEY_LEFT * UNLOCK_FIELD_CHARS ditto for chars to cause unlocking of all fields */ #define LOCK_FIELD_CHARS "!lL" #define UNLOCK_FIELD_CHARS "uU" /* Color configuration. 6 color combinations are used. * Each consists of Foreground and Background colors. * If the color pair are used for input fields then the fore and back * ground colors are reversed when that field is being input/altered. * * ColorPair1 for main header and footer * ColorPair2 for the "ASCII ART" header banner * ColorPair3 for the author sig field, the 2 "help" lines at bottom of * screen, and the clock and labels on the digital audio * details line under main header. * ColorPair4 Digital Audio sample value fields - samplerate, * bits, mono/stereo, buffers etc * ColorPair5 Main central screen fixed layout * ColorPair6 Input value fields in main central screen */ #define ColorPair1 Define_Color(1,COLOR_BLUE,COLOR_GREEN) #define ColorPair2 Define_Color(2,COLOR_YELLOW,COLOR_BLUE) #define ColorPair3 Define_Color(3,COLOR_GREEN,COLOR_RED) #define ColorPair4 Define_Color(4,COLOR_CYAN,COLOR_RED) #define ColorPair5 Define_Color(5,COLOR_WHITE,COLOR_BLUE) #define ColorPair6 Define_Color(6,COLOR_RED,COLOR_CYAN) /* End of USER CONFIGURABLE STUFF ------------------------- */ /* Some color setting macros...... */ #define Define_Color(C,F,B) { init_pair(C,F,B) ; \ init_pair(COLOR_PAIRS-C,B,F); } #ifndef ColorPair1 # define ColorPair1 Define_Color(1,COLOR_BLUE,COLOR_GREEN) #endif #ifndef ColorPair2 # define ColorPair2 Define_Color(2,COLOR_YELLOW,COLOR_BLUE) #endif #ifndef ColorPair3 # define ColorPair3 Define_Color(3,COLOR_GREEN,COLOR_RED) #endif #ifndef ColorPair4 # define ColorPair4 Define_Color(4,COLOR_CYAN,COLOR_RED) #endif #ifndef ColorPair5 # define ColorPair5 Define_Color(5,COLOR_WHITE,COLOR_BLUE) #endif #ifndef ColorPair6 # define ColorPair6 Define_Color(6,COLOR_RED,COLOR_CYAN) #endif /* Set various things depending on what the user configures..... * * If no soundcard stuff, we need to define the AFMT values. * If SUNOS we need to do some extern stuff, and include the correct * string(s).h */ #ifndef NO_DAC_DEVICE #define HAVE_DAC_DEVICE #include #else #define AFMT_QUERY 0 #define AFMT_S16_LE 16 #define AFMT_U8 8 #endif #define QAFMT_QUERY "0" #ifdef SUNOS extern char *sys_errlist[]; extern int sys_nerr; extern char *strrchr(),*strlchr(); #define BIGENDIAN #endif #define EFAIL -1 /* Some useful defines that are common to all programs...... */ /* define the dB function for converting a dB * value to a linear amplitude factor. Assumes and returns double values */ #define dB(X) pow(10,X/20.0) /* and some predefinitions...... */ char *get_conf_value(); #endif /* _config_siggen_h */ siggen-2.3.10/wavsubs.c0000600000175000017500000002255211011656676013364 0ustar jjfamily/* wavsubs.c * Functions for opening, closing, reading, writing WAV files. * Jim Jackson */ /* * Copyright (C) 1998-2008 Jim Jackson jj@franjam.org.uk */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* HISTORY * * 9 Mar 06 RAW write bug fixed * 2 Dec 98 Started */ /* Functions in this file........ * * W is a struct WavValues * * f is a FILE * * * Winit() Set values in WavValues* or if NULL create a new * struct and set values * setendian() tests whether running on a big or little endian machine * riffhdr(f,N) write riff header for file of size N bytes * isriff(f) return TRUE if f is a RIFF format file - skips 1st hdrs * wavreadfmt(f,W) read wav filehdr set Wav file values in *W * returning 0 for ok else errno * wavwritefmt(f,W) write wav filehdr from values in *W * wavread(f,W,buf,N) read samples into buffer buf of size N bytes * return 0 on error (errno refers) or number of samples * wavwrite(f,W,buf,N) write wav samples from buffer buf of size N bytes * fprintfmt(f,W) writes out formatted details from W in ASCII to f * * Macros provided in wavsubs.h for struct WavValues ....... * * NewWavValues() call malloc to get a struct WavValues, return ptr * GetWavSamplerate(W) get the samplerate in *W * SetWavSamplerate(W,S) set samplerate S in *W * GetWavStereo(W) get where stereo samples, 1=stereo, 0=mono * SetWavStereo(W,S) set stereo/mono S in *W * GetWavAFmt(W) get the Audio Format from *W * SetWavAFmt(W,F) set the Audio Format F in *W * GetWavSamples(W) get the number of samples in this chunk * SetWavSamples(W,N) set the number of samples S in *W * * IsWavStereo(W) TRUE if *W has stereo data * IsWavMono(W) TRUE if *W has mono data * IsWav16bit(W) TRUE if *W has 8 bit unsigned data * IsWav8bit(W) TRUE if *W has 16 bit signed, little endian data */ #include #include #include #include "wavsubs.h" int ISBIGENDIAN=0; struct WavValues *Winit(W,Ns,samplerate,afmt,stereo) struct WavValues *W; int Ns,samplerate,afmt,stereo; { if (W==NULL && (W=NewWavValues())==NULL) { errno=ENOMEM; return(NULL); } W->samplerate=samplerate; W->afmt=afmt; W->stereo=stereo; W->Bps=samplerate<<(stereo+(afmt==16)); W->Bypsam=(afmt==8)?1:2; W->samples=Ns; return(W); } setendian() { short int *v,i; i=10; v=&i; ISBIGENDIAN=(*((unsigned char *)v)!=10); } /* isriff(f) read FILE *f and check that it is a RIFF format file. * And is a WAVE chunk. * if so then it returns the length of the file. * FILE *f is left pointing to the WAVE section * if not it returns -1 */ isriff(f) FILE *f; { unsigned char bf[4]; int n,l; n=fread(bf,1,4,f); /* Read the 4 chars "RIFF" */ if ( n!=4 || strncmp(bf,"RIFF",4) ) return(-1); n=fread(bf,1,4,f); /* Read a little endian 32 bit integer */ if (n!=4) return(-1); l=(*bf) + (bf[1]<<8) + (bf[2]<<16) + (bf[3]<<24) ; n=fread(bf,1,4,f); /* Read the 4 chars "RIFF" */ if ( n!=4 || strncmp(bf,"WAVE",4) ) return(-1); return(l); } /* wavnextchunk(f,p) read next WAVE chunk from FILE *f, put name of chunk * in char *p, and retunr length of chunk. * on error return -1 */ wavnextchunk(f,p) FILE *f; char *p; { int n; unsigned char bf[4]; n=fread(p,1,4,f); /* Read the 4 char name of this chunk */ if (n!=4) return(-1); n=fread(bf,1,4,f); /* Read a little endian 32 bit integer */ if (n!=4) return(-1); return((*bf) + (bf[1]<<8) + (bf[2]<<16) + (bf[3]<<24)); } /* findwavchunk(f,s) find next WAVE file chunk with name "s" * when found return length of chunk. * f is positioned at start of chunk. * return -1 if not found */ findwavchunk(f,s) FILE *f; char *s; { int n,i; unsigned char bf[130]; for ( ; ; ) { n=wavnextchunk(f,bf); if (n<0) return(-1); if (strncmp(bf,s,4)==0) return(n); /* if correct chunk return size */ /* otherwise skip this chunk */ for ( ; n>0; n-=i) { /* skip the data for this chunk - to next */ i=(n>128)?128:n; fread(bf,1,i,f); } } } /* wavreadfmt(f,W) read a WAVE header fmt chunk from file stream f * set sample parameters in *W * return -1 if EOF found immediately. Otherwise return an error. */ wavreadfmt(f,W) FILE *f; struct WavValues *W; { unsigned char bf[130]; int n,HL; HL=findwavchunk(f,"fmt "); if (HL<0) return((feof(f))?-1:ferror(f)); if (HL<16 || HL>128) return(EINVAL); /* "fmt " header length must be 16 or more */ n=fread(bf,1,HL,f); /* read fmt block */ if (n!=HL) return((feof(f))?-1:ferror(f)); if (n=Wconvfmt(bf,W)) return(n); HL=findwavchunk(f,"data"); if (HL>0) { W->samples=(HL>>((W->afmt)!=8)); return(0); } return((feof(f))?-1:ferror(f)); } Wconvfmt(p,W) unsigned char *p; struct WavValues *W; { int n; n=(*p) + (p[1]<<8); p+=2; if (n!=1) return(EINVAL); /* PCM data is 1 */ /* no. of chans - convert to stereo/mono ... */ W->stereo=(*p) + (p[1]<<8) - 1; p+=2; /* samplerate ...... */ W->samplerate=(*p)+(p[1]<<8)+(p[2]<<16)+(p[3]<<24); p+=4; /* bytes per sec .... */ W->Bps=(*p)+(p[1]<<8)+(p[2]<<16)+(p[3]<<24); p+=4; /* sample size in bytes ...... */ W->Bypsam=(*p) + (p[1]<<8); p+=2; /* bits per sample....... */ W->afmt=(*p) + (p[1]<<8); p+=2; /* same as afmt :-) */ return(0); } /* riffhdr(f,N) write a RIFF file header to f for size N bytes * return 0 if all ok else retrun errcode */ riffhdr(f,N) FILE *f; unsigned int N; { unsigned char bf[8],*p; p=bf; *p++='R'; *p++='I'; *p++='F'; *p++='F'; *p++=(N)&0xFF; *p++=(N>>8)&0xFF; *p++=(N>>16)&0xFF; *p++=(N>>24)&0xFF; if (fwrite(bf,1,8,f)!=8) return(errno); return(0); } /* wavwritefmt(f,W) write a WAVE header fmt chunk to file stream f * from sample parameters in *W * return 0 if all ok else return error code. */ wavwritefmt(f,W) FILE *f; struct WavValues *W; { unsigned char bf[36],*p; int n,Bps; strncpy(p=bf,"WAVEfmt ",8); p+=8; *p++=16; *p++=0; *p++=0; *p++=0; /* write header length 16 */ *p++=1; *p++=0; /* PCM data has value 1 */ *p++=W->stereo+1; *p++=0; /* Number of channels */ n=W->samplerate; /* write samplerate */ *p++=(n)&0xFF; *p++=(n>>8)&0xFF; *p++=(n>>16)&0xFF; *p++=(n>>24)&0xFF; n=n<<(W->stereo+(W->afmt!=8)); /* Bytes per sec */ *p++=(n)&0xFF; *p++=(n>>8)&0xFF; *p++=(n>>16)&0xFF; *p++=(n>>24)&0xFF; *p++=W->Bypsam; *p++=0; /* Number of bytes per sample */ *p++=W->afmt; *p++=0; /* number of bits per sample */ /* now data section */ *p++='d'; *p++='a'; *p++='t'; *p++='a'; /* "data" section */ n=W->samples<<(W->afmt!=8); /* amount of data in bytes */ *p++=(n)&0xFF; *p++=(n>>8)&0xFF; *p++=(n>>16)&0xFF; *p++=(n>>24)&0xFF; if (fwrite(bf,1,36,f)!=36) return(errno); return(0); } /* wavread(f,W,buf,N) read samples into buffer buf of size N bytes * return 0 on error (errno refers) or number of samples */ wavread(f,W,buf,N) FILE *f; struct WavValues *W; unsigned char *buf; int N; { int s,i,n; unsigned char *p; short int *v; n=fread(buf,1,N,f); if (IsWav8bit(W) || (n==0)) return(n); if (ISBIGENDIAN) { for (v=(short int *)buf, p=buf, i=0; isamplerate,W->Bps,(W->stereo)+1,W->afmt,W->Bypsam); if (W->samplerate) x=(double)((W->samples)>>W->stereo)/(double)(W->samplerate); else x=0; fprintf(f," data samples %5d : duration %7.2f secs.\n", W->samples,x); fflush(f); } siggen-2.3.10/CONFIG.FILES0000600000175000017500000000761211011647553013251 0ustar jjfamily Siggen's Sound Configuration File scheme Jim Jackson ---------------------------------------- Sep 1998 As from siggen version 2.3 onwards a versatile configuration file scheme has been introduced. It allows parameters for all the siggen programs to be specified either across the board, or specifically for particular programs. The Configuration Files Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. All the programs are compiled with the names of the config files built in. The filenames are set in the config.h header file and can be changed. The LOCAL and GLOBAL config files are specified by the settings of: LOCAL #define DEF_CONF_FILENAME ".siggen.conf" GLOBAL #define DEF_GLOBAL_CONF_FILE "/etc/siggen.conf" And can be set to any file name or to NULL to disable the file. The HOME config filename is created using the HOME environment variable and the DEF_CONF_FILENAME together, i.e. using the above, the HOME config file for a user whose home directory is at /home/jj, would be HOME /home/jj/.siggen.conf The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. If no configuration files exist, the programs themselves provide builtin default values (see config.h etc), and most of these values can be set by appropriate command line switches and flags. Configuration Values A configuration value has a name and a value, and values for all programs are set by simply entering a line in the appropriate config file where the first word is the name, followed by arbitrary spaces/tabs, followed by the value. The value is all the rest of that line. e.g. to set the global default samplerate of 44100 samples per sec, the following line would be entered in the GLOBAL config file: SAMPLERATE 44100 Config value names are case insensitive. A config value can be set for a specific program, by prefixing the config value name with the program name and a ':'. e.g. to specify a samplerate of only 8000 samples per sec for the tones program enter TONES:SAMPLERATE 8000 in the relevant config file. If both lines above were in the config file, all programs except tones would use a samplerate of 44100, and tones would use 8000. You do not have to specify all configuration values in the config files. If a particular value is missing, the programs will simply use their builtin defaults (see config.h etc). Configuration values set by command line switches or flags take precedence over values in any of the config files. Beware: the programs do not have their 'name' built-in, but use the name they were invoked by. So if you change the name of a program, remember to change the config file entries. However this does means that by using links to a program, it can be made to pick up a different set of configuration values, depending on the name it is invoked by. Example Configuration File A sample config file is provided in ".siggen.conf". Any line whose first non-whitespace character is a '#', is a comment line and is ignored. What Configuration Values are there? Please see the seperate file CONFIG.VALUES for details of each config value, and which programs use them and what the default builtin values are. The Source and Functions The source for the config functions is in configsubs.c and independant of the rest of the source. The functions can easily be used in other programs to provide configuration facilities. siggen-2.3.10/sweepscr.c0000600000175000017500000003002011011656607013504 0ustar jjfamily/* sweepscr.c * Screen handling for ncurses SweepGEN program * Jim Jackson Oct 99 */ /* * Copyright (C) 1997-2008 * Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #include #include #include #include "scfio.h" #include "sweepgen.h" #include /* set number of millisecs to wait while checking for ESC sequences */ #define KEY_DELAY 25 /* Main screen character strings............ */ char *hl[]={ " /====\\ /====\\ ====== |\\ | ", " | | | | \\ | ", " \\====\\ | | /-\\ /-\\ /--\\ | __ |=== | \\ | ", " | | | | / | / | | | | | | \\ | ", " \\====/ \\/\\/ \\-- \\-- |--/ \\====/ ====== | \\| ", " | ", " Digital Sweep | Generator ", " -----------------------------------------------------------------------------", NULL }; char *oh[]={ " /\\ ", " --/--\\--/-- ", " \\/ ", NULL }; char *sig=" Jim Jackson "; char VERS[128]; int Lsamplerate, /* Local copy of card params to prevent */ LNfb, Lafmt,Lstereo; /* playing being screwed while updating */ /* card characteristics. */ int fragtim; /* Playing Time of one fragment in Microsecs */ char Mchan1[]=" Sweep WaveForm ", Mchan2[]=" Swept WaveForm ", Mstarting[]=" Starting up .......... ", Mwavef[]=" Waveform: ", Mfreq[]= " Frequency: Hz", Mfreq1[]= " Frequency From: Hz To: Hz", Mfreq2[]= " Centre: Hz +/- Hz", Mratio[]=" M/S Ratio: ", Mgain[]= "Hz Gain: ", Msampl[]=" samples/sec x byte ms buffers", Minfo[]=" : ", Mtime[16]="", Mstereo[]="STEREO", Mmono[]= " MONO ", M16b[]= "16 bit", M8b[]= " 8 bit", Mmain[]= "Tab/Return move fields, 'Q'uit, 'S'etup samplerate etc", Mcard[]= "'S'et new values Tab/Return move to next field."; char *Mbits[]={ M8b, M16b, NULL }; char *Mchans[]={ Mmono, Mstereo, NULL }; struct SCField FsamP= { SCF_string, 8, 0, 0, Msampl, 80, 0, 0 }, FsamV= { SCF_integer, 8, 0, 0, &Lsamplerate, 6, 0, 0 }, Fbits= { SCF_option, 8, 19, 0, Mbits, 6, 0, 0 }, Fchans= { SCF_option, 8, 26, 0, Mchans, 6, 0, 0 }, FNfrag= { SCF_integer, 8, 33, 0, &LNfb, 2, 0, 0 }, Ffrag= { SCF_integer, 8, 36, 0, &fragsize, 6, 0, 0 }, Ffragtim= { SCF_integer, 8, 48, 0, &fragtim, 8, 0, 0, 3 }, FinfoP= { SCF_string, 21, 0, 0, Minfo, 80, 0, 0 }, FinfoP2= { SCF_string, 22, 0, 0, Minfo, 80, 0, 0 }, Finfo= { SCF_string, 21, 3, 0, Mstarting, 75, 0, 0 }, Finfo2= { SCF_string, 22, 3, 0, "", 75, 0, 0 }, Ftime= { SCF_string, 8, 69, 0, Mtime, 10, 0, 0 }, Fchan1= { SCF_string, 11, 0, 0, Mchan1, 12, 0, 0 }, Fwav1P= { SCF_string, 12, 2, 0, Mwavef, 12, 0, 0 }, Fwav1V= { SCF_option, 12, 14, 0, NULL, 8, 0, 0 }, FfreqP= { SCF_string, 12, 22, 0, Mfreq, 22, 0, 0 }, FfreqV= { SCF_integer, 12, 34, 0, &freq, 8, 0, 0 }, Fchan2= { SCF_string, 15, 0, 0, Mchan2, 12, 0, 0 }, Fwav2P= { SCF_string, 16, 2, 0, Mwavef, 12, 0, 0 }, Fwav2V= { SCF_option, 16, 14, 0, NULL, 8, 0, 0 }, Ffrq1P= { SCF_string, 16, 22, 0, Mfreq1, 48, 0, 0 }, Ffrq2P= { SCF_string, 17, 22, 0, Mfreq2, 48, 0, 0 }, FfrqFV= { SCF_integer, 16, 39, 0, &freqF, 8, 0, 1 }, FfrqTV= { SCF_integer, 16, 56, 0, &freqT, 8, 0, 2 }, FfrqCV= { SCF_integer, 17, 39, 0, &freqC, 8, 0, 3 }, FfdevV= { SCF_integer, 17, 56, 0, &frdev, 8, 0, 4 }, Fgn2P= { SCF_string, 16, 40, 0, Mgain, 10, 0, 0 }, Fgn2V= { SCF_integer, 16, 50, 0, &Gain2, 6, 0, 3 }; struct SCField *CHhdrs[]= { &Fchan1, &Fwav1P, &FfreqP, &Fchan2, &Fwav2P, &Ffrq1P, &Ffrq2P, /* &Fgn2P, */ NULL }, *CHvals[]= { &Fwav1V, &FfreqV, &Fwav2V, &FfrqFV, &FfrqTV, &FfrqCV, &FfdevV, /* &Fgn2V, */ NULL }, *scrP[]= { &FsamP, &FinfoP, &FinfoP2, &Finfo, &Finfo2, &Ffrag, &Ffragtim, &Ftime, NULL, }, *scrV[]= { &FsamV, &Fbits, &Fchans, &FNfrag, NULL }; /* Help strings for second info line. */ char Hwav[]="DOWN ARROW (or SPACE) & UP ARROW to select WaveForm", Hnum[]="Enter Digits, DEL or <- to delete, LEFT/RIGHT move digits, UP/DOWN Inc/Dec", Hbits[]="Press to toggle 8 / 16 bit setting", Hchan[]="Press to toggle Mono / Stereo setting"; char *Hvals[]={ Hwav, Hnum, Hwav, Hnum, Hnum, Hnum, Hnum, NULL }; char *Hset[]= { Hnum, Hbits, Hchan, Hnum, NULL }; /* waveform name and buffer array....... */ char **WAVEFORMS=NULL; int **wavbufs=NULL; /* WinGen() The main interactive screen */ WinGen(fd) int fd; { int c,i,n,st,t; unsigned int j,k; int f,wavef,card; char **hh; struct SCField **ff; if (n=WinGenInit()) return(n); hh=Hvals; ff=CHvals; doinfo(Mmain,0,&Finfo2); wavef=card=f=0; dispfield(ff,hh,&Finfo,f); refresh(); t=time(NULL); for (;;) { if ((i=time(NULL))-t) { t=i; dotime(&Ftime); } if (playsamples(fd)<0) { move(COLS-1,0); endwin(); return(err_rpt(errno,"Problem generating output samples.")); } if ((c=getch())==-1) { delay(25000); continue; } if (c=='s' || c=='S') { if (card) { /* check if card params have changed - if so close and reopen */ Lafmt=(Fbits.adj)?AFMT_S16_LE:AFMT_U8; Lstereo=Fchans.adj; if ((Lsamplerate!=samplerate) || (Lafmt!=afmt) || (Lstereo!=stereo) || (LNfb!=Nfragbufs)) { close(fd); if ((fd=DACopen(dac,"w",&Lsamplerate,&Lafmt,&Lstereo))<0 || (fragsize=setfragsize(fd,LNfb,Bufspersec,Lsamplerate,Lafmt,Lstereo))<0) { move(COLS-1,0); endwin(); return(err_rpt(errno,dac)); } fragsamplesize=(fragsize>>(Lafmt==AFMT_S16_LE))>>(Lstereo); fragtim=fragsamplesize*1000000/Lsamplerate; putfield(&Ffrag); putfield(&Ffragtim); } dofields(scrV); /* if samplerate or format has changed, re-generate waveforms */ /* we generate 16 bit samples cos we need it for sweeping freq */ /* then we adjust if we are writing 8 bit samples */ if ((Lsamplerate!=samplerate) || (Lafmt!=afmt)) { if (st=genAllWaveforms(&WAVEFORMS,&wavbufs,1,Lsamplerate*resolution,AFMT_S16_LE)) { move(COLS-1,0); endwin(); return(err_rpt(st,"Problem generating Base waveforms.")); } } samplerate=Lsamplerate; afmt=Lafmt; stereo=Lstereo; Nfragbufs=LNfb; playsamples(-1); /* resync left and right channels */ dispfield(ff,hh,&Finfo,f); card=0; f=wavef; ff=CHvals; hh=Hvals; doinfo(Mmain,0,&Finfo2); } else { /* enter card setting alteration stuff */ dispfield(ff,hh,&Finfo,f); card=1; wavef=f; ff=scrV; hh=Hset; f=next_field(ff,-1); doinfo(Mcard,0,&Finfo2); } dispfield(ff,hh,&Finfo,f); continue; } if (c=='q' || c=='Q') { move(COLS-1,0); endwin(); return(c); } f=doinput(c,ff,hh,&Finfo,f); if (i=(ff[f]->id)) { if (i<=2) { freqC=(freqF+freqT+1)/2; frdev=((freqT>freqF)?freqT:freqF)-freqC; } else { if ((i==3) && (freqC\n"); getchar(); } initscr(); cbreak(); noecho(); nonl(); intrflush(stdscr,FALSE); keypad(stdscr,TRUE); nodelay(stdscr,TRUE); timeout(KEY_DELAY); if (has_colors()) { start_color(); ColorPair1; ColorPair2; ColorPair3; ColorPair4; ColorPair5; ColorPair6; att_h1=COLOR_PAIR(1); att_h2=COLOR_PAIR(2)+A_BOLD; att_h3=COLOR_PAIR(3); att_h4=COLOR_PAIR(4); att_h5=COLOR_PAIR(5); att_h6=COLOR_PAIR(6); } else { att_h1=A_REVERSE; att_h5=att_h6=att_h2=att_h4=A_BOLD; att_h3=A_NORMAL; } dofatt(scrV,att_h4); dofatt(scrP,att_h3); Ffrag.attr=Ffragtim.attr=att_h4; dofatt(CHhdrs,att_h5); dofatt(CHvals,att_h6); sprintf(VERS,VERSTR,sys,VERSION); dohdr(0,att_h1,att_h2,att_h3,hl,oh,sig,VERS); for (i=FsamP.row; i>8)+128) /* (afmt==AFMT_S16_LE) */ /* It's all done in signed 16 bit format - because we need the * precision for the sweeping waveform. We adjust down to 8 bit * if writing 8 bit samples on output. */ dev=(freqF #include #include #include "scfio.h" #include "siggen.h" #include /* set number of millisecs to wait while checking for ESC sequences */ #define KEY_DELAY 25 /* Main screen character strings............ */ char *hl[]={ " /====\\ /====\\ ====== |\\ | ", " | | | | \\ | ", " \\====\\ o /--\\ | __ |=== | \\ | ", " | | | | | | | | \\ | ", " \\====/ | \\--| \\====/ ====== | \\| ", " | ", " Digital \\--/ Signal Generator ", " -----------------------------------------------------------------------------", NULL }; char *oh[]={ " /\\ ", " --/--\\--/-- ", " \\/ ", NULL }; char *sig=" Jim Jackson "; char VERS[128]; int Lsamplerate, /* Local copy of card params to prevent */ LNfb, Lafmt,Lstereo; /* playing being screwed while updating */ /* card characteristics. */ int fragtim; /* Playing Time of one fragment in Microsecs */ char Mchan1[]=" Channel 1 ", Mchan2[]=" Channel 2 ", Mstarting[]=" Starting up .......... ", Mwavef[]=" Waveform: ", Mfreq[]= " Frequency: ", Mgain[]= "Hz Gain: ", Mphase[]="Phase: deg.", Mratio[]=" M/S Ratio: ", Moffs[]= "Phaseshift: ", Msampl[]=" samples/sec x byte ms buffers", Minfo[]=" : ", Mtime[16]="", Mstereo[]="STEREO", Mmono[]= " MONO ", M16b[]= "16 bit", M8b[]= " 8 bit", Mmain[]= "Tab/Return move fields, 'R'esync channels, 'Q'uit, 'S'etup samplerate etc", Mcard[]= "'S'et new values Tab/Return move to next field."; char *Mbits[]={ M8b, M16b, NULL }; char *Mchans[]={ Mmono, Mstereo, NULL }; char *Mtrack[]={ " ", "tracking ||", NULL }; struct SCField FsamP= { SCF_string, 8, 0, 0, Msampl, 80, 0, 0, 0 }, FsamV= { SCF_integer, 8, 0, 0, &Lsamplerate, 6, 0, 0, 0 }, Fbits= { SCF_option, 8, 19, 0, Mbits, 6, 0, 0, 0 }, Fchans= { SCF_option, 8, 26, 0, Mchans, 6, 0, 0, 0 }, FNfrag= { SCF_integer, 8, 33, 0, &LNfb, 2, 0, 0, 0 }, Ffrag= { SCF_integer, 8, 36, 0, &fragsize, 6, 0, 0, 0 }, Ffragtim= { SCF_integer, 8, 48, 0, &fragtim, 8, 0, 0, 3 }, FinfoP= { SCF_string, 21, 0, 0, Minfo, 80, 0, 0, 0 }, FinfoP2= { SCF_string, 22, 0, 0, Minfo, 80, 0, 0, 0 }, Finfo= { SCF_string, 21, 3, 0, Mstarting, 75, 0, 0, 0 }, Finfo2= { SCF_string, 22, 3, 0, "", 75, 0, 0, 0 }, Ftime= { SCF_string, 8, 69, 0, Mtime, 10, 0, 0, 0 }, Fchan1= { SCF_string, 11, 0, 0, Mchan1, 12, 0, 0, 0 }, Fwav1P= { SCF_string, 12, 2, 0, Mwavef, 12, 0, 0, 0 }, Fwav1V= { SCF_option, 12, 14, 0, NULL, 8, 0, 0, 0 }, Ffrq1P= { SCF_string, 12, 22, 0, Mfreq, 12, 0, 0, 0 }, Ffrq1V= { SCF_integer, 12, 34, 0, &freq, 8, 0, 0, 1 }, Fgn1P= { SCF_string, 12, 42, 0, Mgain, 10, 0, 0, 0 }, Fgn1V= { SCF_integer, 12, 51, 0, &Gain, 6, 0, 0, 3 }, FtrWav= { SCF_option, 14, 10, 0, Mtrack, 11, 0, 0, 0 }, FtrFrq= { SCF_option, 14, 29, 0, Mtrack, 11, 0, 0, 0 }, FtrGn= { SCF_option, 14, 44, 0, Mtrack, 11, 0, 0, 0 }, Fchan2= { SCF_string, 15, 0, 0, Mchan2, 12, 0, 0, 0 }, Fwav2P= { SCF_string, 16, 2, 0, Mwavef, 12, 0, 0, 0 }, Fwav2V= { SCF_option, 16, 14, 0, NULL, 8, 0, 0, 0 }, Ffrq2P= { SCF_string, 16, 22, 0, Mfreq, 12, 0, 0, 0 }, Ffrq2V= { SCF_integer, 16, 34, 0, &freq2, 8, 0, 0, 1 }, Fgn2P= { SCF_string, 16, 42, 0, Mgain, 10, 0, 0, 0 }, Fgn2V= { SCF_integer, 16, 51, 0, &Gain2, 6, 0, 0, 3 }, FphP= { SCF_string, 16, 60, 0, Mphase, 18, 0, 0, 0 }, FphV= { SCF_integer, 16, 67, 0, &phase, 6, 0, 0, 0 }; /* These arrays define groups of SCFields that are used together. * CHhdrs[] is the array of titles for the generation parameters * for the 2 channels, this displayed at init. * CHvals[] is the array of generation input parameter fields that * are cycled round and altered. * scrP[] array of screen titles for soundcard config and status lines * scrV[] array of soundcard config values */ struct SCField *CHhdrs[]= { &Fchan1, &Fwav1P, &Ffrq1P, &Fgn1P, &Fchan2, &Fwav2P, &Ffrq2P, &Fgn2P, &FphP, NULL }, *CHvals[]= { &Fwav1V, &Ffrq1V, &Fgn1V, &Fwav2V, &Ffrq2V, &Fgn2V, &FphV, NULL }, *scrP[]= { &FsamP, &FinfoP, &FinfoP2, &Finfo, &Finfo2, &Ffrag, &Ffragtim, &Ftime, NULL, }, *scrV[]= { &FsamV, &Fbits, &Fchans, &FNfrag, NULL }; /* * TRKvals[] is the array of fields holding and displaying the tracking * values for the waveform, frequency and gain fields * it has same numbers of elements as CHvals[] and has same * tracking field def for the fields that can track. * TRKpairs[] is an array of integers of same size as CHvals. * if CHvals[i] entry has a possible tracking partner * it is CHvals[TRKpairs[i]]. When tracking, changing one * value of a pair, alters its partner's setting too. * entry of -1 indicates no tracking partner. */ struct SCField *TRKvals[]= { &FtrWav, &FtrFrq, &FtrGn, &FtrWav, &FtrFrq, &FtrGn, NULL, NULL }; int TRKpairs[]= { 3, 4, 5, 0, 1, 2, -1 }; /* Help strings for second info line. */ char Hwav[]="DOWN ARROW (or SPACE) & UP ARROW to select WaveForm", Hnum[]="Enter Digits, DEL or <- to delete, LEFT/RIGHT move digits, UP/DOWN Inc/Dec", Hbits[]="Press to toggle 8 / 16 bit setting", Hchan[]="Press to toggle Mono / Stereo setting"; char *Hvals[]={ Hwav, Hnum, Hnum, Hwav, Hnum, Hnum, Hnum, NULL }; char *Hset[]= { Hnum, Hbits, Hchan, Hnum, NULL }; /* waveform name and buffer array....... */ char **WAVEFORMS=NULL; int **wavbufs=NULL; /* WinGen() The main interactive screen */ WinGen(fd) int fd; { int c,i,n,st,t; int X,Y; int f,wavef,card; char **hh; struct SCField **ff; WinGenInit(); hh=Hvals; ff=CHvals; doinfo(Mmain,0,&Finfo2); wavef=card=f=0; dispfield(ff,hh,&Finfo,f); refresh(); t=time(NULL); for (;;) { if ((i=time(NULL))-t) { t=i; dotime(&Ftime); } if (playsamples(fd)<0) { move(COLS-1,0); endwin(); return(err_rpt(errno,"Problem generating output samples.")); } if ((c=getch())==-1) { delay(25000); continue; } if (c=='s' || c=='S') { if (card) { /* check if card params have changed - if so close and reopen */ Lafmt=(Fbits.adj)?AFMT_S16_LE:AFMT_U8; Lstereo=Fchans.adj; if ((Lsamplerate!=samplerate) || (Lafmt!=afmt) || (Lstereo!=stereo) || (LNfb!=Nfragbufs)) { close(fd); if ((fd=DACopen(dac,"w",&Lsamplerate,&Lafmt,&Lstereo))<0 || (fragsize=setfragsize(fd,LNfb,Bufspersec,Lsamplerate,Lafmt,Lstereo))<0) { move(COLS-1,0); endwin(); return(err_rpt(errno,dac)); } fragsamplesize=(fragsize>>(Lafmt==AFMT_S16_LE))>>(Lstereo); fragtim=fragsamplesize*1000000/Lsamplerate; putfield(&Ffrag); putfield(&Ffragtim); } dofields(scrV); /* if samplerate or format has changed, re-generate waveforms */ if ((Lsamplerate!=samplerate) || (Lafmt!=afmt)) { if (st=genAllWaveforms(&WAVEFORMS,&wavbufs,1,Lsamplerate*resolution,Lafmt)) { move(COLS-1,0); endwin(); return(err_rpt(st,"Problem generating Internal waveforms.")); } } samplerate=Lsamplerate; afmt=Lafmt; stereo=Lstereo; Nfragbufs=LNfb; playsamples(-1); /* resync left and right channels */ dispfield(ff,hh,&Finfo,f); card=0; f=wavef; ff=CHvals; hh=Hvals; doinfo(Mmain,0,&Finfo2); } else { /* enter card setting alteration stuff */ dispfield(ff,hh,&Finfo,f); card=1; wavef=f; ff=scrV; hh=Hset; f=next_field(ff,-1); doinfo(Mcard,0,&Finfo2); } dispfield(ff,hh,&Finfo,f); continue; } if (c=='q' || c=='Q') { move(COLS-1,0); endwin(); return(c); } if (c=='r' || c=='R') { playsamples(-1); /* synch left and right channels */ continue; } if ((c=='t' || c=='T') && (i=(TRKpairs[f]))>=0) { /* if there is an id value then it can track */ n=!(GetOptionIndex(TRKvals[i])); SetOptionIndex(TRKvals[i],n); getyx(stdscr,Y,X); putfield(TRKvals[i]); move(Y,X); } else { f=doinput(c,ff,hh,&Finfo,f); } if ((i=TRKpairs[f])>=0 && GetOptionIndex(TRKvals[i])) { scfeql(ff[i],ff[f]); getyx(stdscr,Y,X); putfield(ff[i]); move(Y,X); } refresh(); } } WinGenInit() { int att_h1,att_h2,att_h3,att_h4,att_h5,att_h6; int n,i; Lsamplerate=samplerate; /* set local working copy of samplerate */ Lafmt=afmt; Lstereo=stereo; LNfb=Nfragbufs; Fbits.adj=(afmt==16); Fchans.adj=stereo; fragtim=fragsamplesize*1000000/samplerate; if (n=genAllWaveforms(&WAVEFORMS,&wavbufs,1,samplerate*resolution,afmt)) { return(err_rpt(n,"Problem generating Internal waveforms.")); } Fwav1V.val.sp=WAVEFORMS; Fwav2V.val.sp=WAVEFORMS; setwaveform(&Fwav1V,wf,WAVEFORMS); setwaveform(&Fwav2V,wf2,WAVEFORMS); n=0; /* setup the correct number of Decimal points depending on resolution */ if (resolution==10) n=1; else if (resolution==100) n=2; Ffrq1V.dp=Ffrq2V.dp=n; freq*=resolution; freq2*=resolution; tzset(); /* set timezone stuff up for dotime() function */ if (vflg) { /* ========= if vflg pause before going into ncurses =======*/ printf("\n\n"); getchar(); } initscr(); /* ============== for here on in ncurses active ==============*/ cbreak(); noecho(); nonl(); intrflush(stdscr,FALSE); keypad(stdscr,TRUE); nodelay(stdscr,TRUE); timeout(KEY_DELAY); if (has_colors()) { start_color(); ColorPair1; ColorPair2; ColorPair3; ColorPair4; ColorPair5; ColorPair6; att_h1=COLOR_PAIR(1); att_h2=COLOR_PAIR(2)+A_BOLD; att_h3=COLOR_PAIR(3); att_h4=COLOR_PAIR(4); att_h5=COLOR_PAIR(5); att_h6=COLOR_PAIR(6); } else { att_h1=A_REVERSE; att_h5=att_h6=att_h2=att_h4=A_BOLD; att_h3=A_NORMAL; } dofatt(scrV,att_h4); dofatt(scrP,att_h3); Ffrag.attr=Ffragtim.attr=att_h4; dofatt(CHhdrs,att_h5); dofatt(CHvals,att_h6); dofatt(TRKvals,att_h5); sprintf(VERS,VERSTR,sys,VERSION); dohdr(0,att_h1,att_h2,att_h3,hl,oh,sig,VERS); for (i=FsamP.row; i32767)?32767:((t<-32767)?-32767:t)); /* t=(5000+(((long long)(wv2[tof2]))*(long long)Gain2))/(long long)10000; */ t=(500+(((int)(wv2[tof2]))*Gain2))/1000; *vp++=(short int)((t>32767)?32767:((t<-32767)?-32767:t)); of1=(of1+freq)%(samplerate*resolution); tof2=(tof2+freq2)%(samplerate*resolution); } } else { for (i=0, vp=(short int *)frag; i32767)?32767:((t<-32767)?-32767:t)); of1=(of1+freq)%(samplerate*resolution); tof2=(tof2+freq2)%(samplerate*resolution); } } } else { /* afmt is 8 bit */ w1=(unsigned char *)(wavbufs[Fwav1V.adj]); w2=(unsigned char *)(wavbufs[Fwav2V.adj]); if (stereo) { for (i=0, p=frag; i255)?255:((t<0)?0:t)); /* t=128+(5000+((int)(w2[tof2])-128)*Gain2)/10000; */ t=128+(500+(((int)(w2[tof2])-128)*Gain2))/1000; *p++=(unsigned char)((t>255)?255:((t<0)?0:t)); of1=(of1+freq)%(samplerate*resolution); tof2=(tof2+freq2)%(samplerate*resolution); } } else { for (i=0, p=frag; i255)?255:((t<0)?0:t)); of1=(of1+freq)%(samplerate*resolution); tof2=(tof2+freq2)%(samplerate*resolution); } } } /* afmt==AFMT_S16_LE */ of2=(tof2-ph+(samplerate*resolution))%(samplerate*resolution); /* remove phase from generator offset */ if (write(fd,frag,fragsize)<0) return(-1); } return(0); } siggen-2.3.10/Makefile0000600000175000017500000000652711011646555013165 0ustar jjfamily# # Makefile for jj's siggen ..... SHELL = /bin/sh # Version of siggen V = 2.3 # Edit PROGS to make the programs you want. You may wish to omit smix # if you do not want yet another mixer program. PROGS = tones sgen swgen siggen sweepgen fsynth soundinfo smix # TEXTS = tones.txt sgen.txt swgen.txt siggen.txt sweepgen.txt soundinfo.txt smix.txt fsynth.txt siggen.conf.txt # # simple command line programs...... TONES = tones.o tonesgen.o generator.o misc.o wavfile.o wavsubs.o DAC.o configsubs.o SGEN = sgen.o generator.o misc.o wavfile.o wavsubs.o DAC.o configsubs.o SWGEN = swgen.o generator.o misc.o wavfile.o wavsubs.o DAC.o configsubs.o SMIX = smix.o mixer.o configsubs.o # # curses based programs...... FSYNTH = fsynth.o fsynscr.o scrsubs.o generator.o misc.o DAC.o scfio.o configsubs.o SIGGEN = siggen.o sigscr.o scrsubs.o generator.o misc.o DAC.o scfio.o configsubs.o SWEEPGEN = sweepgen.o sweepscr.o scrsubs.o generator.o misc.o DAC.o scfio.o configsubs.o # srcdir = . includedir = /usr/include/ncurses INSDIR = /usr/local/bin MANDIR = /usr/local/man LOCALINS = $(HOME)/bin LOCALMAN = $(HOME)/man CC = gcc CFLAGS = -O2 CPPFLAGS = -I. -I$(includedir) CCFLAGS = $(CFLAGS) $(CPPFLAGS) LINK = $(CC) LDFLAGS = -lncurses -lm .c.o: config.h $(CC) -c $(CCFLAGS) $< all: $(PROGS) $(TEXTS) text: $(TEXTS) %.txt: %.5 nroff -man $< | col -b -x > $@ %.txt: %.1 nroff -man $< | col -b -x > $@ mixer.o: mixer.c mixer.h smix.o: smix.c mixer.h config.h scfio.o: scfio.c scfio.h scrsubs.o: scrsubs.c scfio.h config.h sigscr.o: sigscr.c scfio.h config.h siggen.h sigscr-1.o: sigscr-1.c scfio.h config.h sweepscr.o: sweepscr.c scfio.h config.h sweepgen.h fsynscr.o: fsynscr.c scfio.h fsynth.h config.h fsynth.o: fsynth.c fsynth.h config.h install: @echo "2 install options :-" @echo " make sysinstall" @echo " into $(INSDIR) and $(MANDIR)" @echo " make localinstall" @echo " into $(LOCALINS) and $(LOCALMAN)" localinstall: $(PROGS) @strip $(PROGS) @chmod 755 $(PROGS) @echo "Copying $(PROGS) to $(LOCALINS)" @cp -p $(PROGS) $(LOCALINS) @for n in $(PROGS) ; do \ chmod 644 $$n.1 ; \ echo "Copying $$n.1 to $(LOCALMAN)/man1/$$n.1" ; \ cp -p $$n.1 $(LOCALMAN)/man1/$$n.1 ; \ done @cp -p siggen.conf.5 $(LOCALMAN)/man5 @chmod 644 $(LOCALMAN)/man5/siggen.conf.5 sysinstall: $(PROGS) @strip $(PROGS) @chmod 755 $(PROGS) @echo "Copying $(PROGS) to $(INSDIR)" @cp -p $(PROGS) $(INSDIR) @for n in $(PROGS) ; do \ chmod 644 $$n.1 ; \ echo "Copying $$n.1 to $(MANDIR)/man1/$$n.1" ; \ cp -p $$n.1 $(MANDIR)/man1/$$n.1 ; \ done @cp -p siggen.conf.5 $(MANDIR)/man5 @chmod 644 $(MANDIR)/man5/siggen.conf.5 nodac: make -f Makefile.NODAC all vu: $(VU) $(CC) $(VU) -o $@ soundinfo: soundinfo.o $(CC) $@.o -o $@ sgen: $(SGEN) $(CC) $(SGEN) -lm -o $@ swgen: $(SWGEN) $(CC) $(SWGEN) -lm -o $@ tones: $(TONES) $(CC) $(TONES) -lm -o $@ fsynth: $(FSYNTH) fsynth.h $(CC) $(FSYNTH) $(LDFLAGS) -o $@ siggen: $(SIGGEN) siggen.h $(CC) $(SIGGEN) $(LDFLAGS) -o $@ siggen-1: $(SIGGEN1) siggen.h $(CC) -DVERSION1 $(SIGGEN1) $(LDFLAGS) -o $@ sweepgen: $(SWEEPGEN) sweepgen.h $(CC) $(SWEEPGEN) $(LDFLAGS) -o $@ smix: $(SMIX) mixer.h $(CC) $(SMIX) $(LDFLAGS) -o $@ clean: rm -rf *.o $(PROGS) $(TEXTS) *~ dist: make clean (cd tones.eg; make clean) (cd contrib; make clean) (d=`basename $$PWD` ; cd .. ; tar cfz $$d.tgz $$d) siggen-2.3.10/CHANGES0000600000175000017500000000777507340023354012522 0ustar jjfamily siggen - a package of waveform generation programs for linux ------------------------------------------------------------ Version 2.3.+ siggen Tried adding loadable waveforms - came to an impasse. I will revisit this. Added a "tracking" feature suggested by Gart Reese. 't' or 'T' while in the waveform, frequency or gain fields will cause both similar fields of each channel to track, i.e. have the same value. A "tracking" message shows which fields are currently tracking. Repeating 't' or 'T' cancels the tracking of the fields. fsynth A curses based "fourier" synthesis program. Allows a mixture of a fundamental sine wave and varying proportions of it's harmonics to be mixed to create complex waveforms. tones Added loadable waveforms. Tones can load a waveform from a WAV file that contains exactly one seconds worth of samples, at the same samplerate as tones is using and same format etc, and it will "play" from the these samples. The waveform name is the basename of the wav file with directory and any suffix removed. To work correctly the samples should be for a 1Hz wave. If its for say a 2Hz wave then the frequencies generated will all be double for that waveform. Added recursive command file reading. Attenuation/gain levels added, thanks to "Mark E. Shoulson" for a patch, feedback and comments. Fixed faulty mixing code for more than 2 channels. All curses progs The ability to "Lock" input field to freeze values. Locked fields are skipped while moving around the screen. All locked fields can be unlocked in one go to reset. '!' or 'L' locks the current field, 'U' unlocks all locked fields. This was the result of misunderstanding an idea from Garst! Also added ability to redraw screen by pressing Ctrl-L (^L), useful if screen gets garbled. Bug fix in scfio.c, thanks to "Garst R. Reese" for use egcs and finding the bug - I think gcc was too forgiving. All progs Added configuration file(s) support. Version 2.2 tones, sgen, swgen Added ability to compile on machines without sound support, so that WAV and raw data files can be created. Fixed so can be compiled under SUNOS on sparc machines. This meant fixing the implicit little endian nature of the raw and wav file writing code. New config.h file added with user configurable options gathered together in one place, for global options. tones, sgen, swgen Added the -x10 and -x100 options, which when in use allow the generation of freq. to the nearest 0.1Hz or 0.01Hz by forcing the specification of all frequencies to be 10 or 100 times too big. e.g. swgen -x10 -2 -v 2 2000 20000 causes stereo samples for a 0.2Hz sawtooth ramp sweeping a sin wave from 200Hz to 2000Hz. Version 2.1 Fixed compilation problem of incompatible extern declaration of sys_errlist . extern wasn't necessary so deleted it. Version 2 Added swgen - a swept frequency generator. Added sweepgen - a curses based swept freq. generator Changed siggen to play continuously - changes to waveform, freq, gain etc take effect (almost) immediately. Downside is that this is a lot more processor intensive. Fine, just, on my 486DX2/66. Extended the tones program, extensively. Added dtmf program which can be used as tone phone dialer. Fixed mixed up description of sawtooth/triangle waves in sgen manual. Version 1.1 released xx March 1997 Fixed a small initialise bug in sgen - reported by Michael Meifert (Michael this email address doesn't work) Fixed a bug in siggen that prevented PULSE waveforms being generated Added the tones program following a suggestion by Michael who wanted a program to generate tones to control a radio repeater (I think). Version 1 released 6 March 1997 contained programs sgen, siggen, smix, soundinfo siggen-2.3.10/CONFIG.VALUES0000600000175000017500000001241207340024635013400 0ustar jjfamily Complete List of Configuration Values used by SIGGEN progams ------------------------------------------------------------ Name sgen swgen tones siggen sweepgen fsynth smix -------- ---- ----- ----- ------ -------- ------ ---- BUFFSPERSEC N N N Y Y Y N CHANNELS Y Y Y Y Y Y N DACFILE Y Y Y Y Y Y N FRAGMENTS N N N Y Y Y N LOADABLE_WAVEFORMS N N Y N N N N MIXERFILE N N N N N N Y SAMPLERATE Y Y Y Y Y Y N SAMPLESIZE Y Y Y Y Y Y N VERBOSE Y Y Y Y Y Y Y VI_KEYS N N N Y Y Y N Configuration Value Details --------------------------- BUFFSPERSEC The number of sound buffer fragments to play every second. This is used to calculate the size of the buffer fragments, to the nearest power of 2. see FRAGMENTS below for a fuller discussion. CHANNELS In all programs except tones and fsynth, channels specifies the number of output channels to use, i.e. 1 for Mono and 2 for Stereo. For tones, channels specifies the number of 'voices' on which tones can generate different waveforms before mixing them into the one output channel. For fsynth, channels specifies the numbers of seperately configurable oscillators used to mix the single output channel. DACFILE The Digital to Analogue Converter (or PCM of DSP) device on which to output the generated samples. This must be a real OSS PCM device, otherwise the ioctls used will fail. FRAGMENTS The number of Audio Buffer fragments to configure in the driver. The interactive programs respond to changes made to parameters from the keyboard immediately, but data will be buffered in driver in the buffer fragments. If the amount of data buffered is too much then there will very noticable delays before the output sound is altered. Against that, insufficient buffering may mean that there is not enough data buffered for output to cover the time when other processes are being run by the scheduler. The programs set the buffer size so that aprox. BUFFSPERSEC buffers are played every second. Hence there will be (FRAGMENTS/BUFFSPERSEC) seconds worth of samples buffered. Hence if FRAGMENTS is set to 3, and BUFFSPERSEC set to 15, there will be aprox. 3/15 = 0.2 secs worth of sound buffered for output. On a lightly loaded fast machine this, should be sufficient. To cover periods of heavy load or on a less powerful machine set FRAGMENTS to 4 or 5, or set BUFFSPERSEC to a lower value. But remember the interactive programs will appear sluggish in responding to the keyboard. LOADABLE_WAVEFORMS Number of loadable waveforms allowed. MIXERFILE The mixer device to control. This must be a real OSS mixer device, otherwise the ioctls used will fail. SAMPLERATE The number of samples per second to use. If output is to the DAC then the DAC device is set to output samples at this rate. BEWARE: not all cards can support all samplerates. SoundBlasters are fairly flexible in this respect. Other cheaper cards are not. Indeed some cards can only handle a very restricted set of related samplerates e.g. 11025, 22050, 44100 & 8000, 16000, 32000, 48000. When writing to DACFILE all programs will attempt to set the samplerate given, but use the actual samplerate the device used. Use the verbose command line flag to check actual samplerates used. 8000 is the samplerate used in the phone system with 8 bit samples, and is adequate for voice range frequencies. 44100 is the samplerate used in audio CDs 48000 is the samplerate used in DAT systems, I think. 32000 is also used, but I forget where. In general, the higher the samplerate the larger the memory and processing requirement, but the higher the frequency range and the more accurate the signals generated. SAMPLESIZE Number of bits per sample. Only two values are allowed currently, 8 or 16. 8 bit samples are unsigned, with decimal value 128 being the 'zero' level. 16 bit samples are signed little endian values, i.e. the least significant byte comes before the most significant byte either in a file, or in the byte stream to an output device. If samplesize if left completely unspecified, then all programs will attempt to do 16 bit samples to DACFILE, and if that isn't possible will do 8 bit samples. Or if writing to a file, 16 bit samples will be written. VERBOSE sets verbosity level. 0 - is quiet 1 - is be a bit verbose (equiv. to -v switch) 2 - is be very verbose (equiv. to -vv switch) VI_KEYS if set to a non-zero value, then the VI cursor moving keys "HJKL" are enabled. siggen-2.3.10/dB.c0000600000175000017500000000202707041145347012206 0ustar jjfamily/* dB.c * converts dB valuesgiven as parameters into linear ratio values * i.e. dB 20 will give the value 10 * dB 26 will give the value 20 * dB 0 1 */ #include #define db(x) pow(10,x/20.0) main(argc,argv) int argc; char **argv; { int i,j,k,n,inv; double x; argc--; argv++; for ( inv=0 ; argc; argc--, argv++) { if (strcmp(*argv,"-i")==0) { inv=1; continue; } x=(double)(atoi(*argv)); if (inv==0) printf("%fdB = %f times\n",x,db(x)); else printf("%fdB = %f times\n",20.0*log10(x),x); } } /* double db(x) double x; { return(pow(10,x/20.0); } */ /* db(x) int x; { int i; static int dB_Conv[20]={ 100000000, 112201845, 125892541, 141253754, 158489319, 177827941, 199526231, 223872114, 251188643, 281838293, 316227766, 354813389, 398107171, 446683592, 501187234, 562341325, 630957344, 707945784, 794328235, 891250938 }; for (i=100000000; i && x>=20; x-=20) { i/=10; } return((i)?(dB_Conv[x]/i):-1); } */ siggen-2.3.10/fmtheaders.h0000600000175000017500000000506210404117225014001 0ustar jjfamily/* Taken from the sndkit distribution * * Autor: Michael Beck - beck@informatik.hu-berlin.de * Amended: Jim Jackson - jj@franjam.org.uk * * changes: * * Alterations to cope with little endian and big endian machines. * Original assumed only x86 type. * * audio structure additions at end */ #ifndef _FMTHEADERS_H #define _FMTHEADERS_H 1 #include /* Definitions for .VOC files */ #define MAGIC_STRING "Creative Voice File\0x1A" #define ACTUAL_VERSION 0x010A #define VOC_SAMPLESIZE 8 #define MODE_MONO 0 #define MODE_STEREO 1 #define DATALEN(bp) ((u_long)(bp->datalen) | \ ((u_long)(bp->datalen_m) << 8) | \ ((u_long)(bp->datalen_h) << 16) ) typedef struct _vocheader { u_char magic[20]; /* must be MAGIC_STRING */ u_short headerlen; /* Headerlength, should be 0x1A */ u_short version; /* VOC-file version */ u_short coded_ver; /* 0x1233-version */ } VocHeader; typedef struct _blocktype { u_char type; u_char datalen; /* low-byte */ u_char datalen_m; /* medium-byte */ u_char datalen_h; /* high-byte */ } BlockType; typedef struct _voice_data { u_char tc; u_char pack; } Voice_data; typedef struct _ext_block { u_short tc; u_char pack; u_char mode; } Ext_Block; /* Definitions for Microsoft WAVE format */ #define RIFF "RIFF" #define WAVE "WAVE" #define FMT "fmt " #define DATA "data" #define PCM_CODE 1 #define WAVE_MONO 1 #define WAVE_STEREO 2 /* it's in chunks like .voc and AMIGA iff, but my source say there * are in only in this combination, so I combined them in one header; * it works on all WAVE-file I have */ typedef struct _waveheader { char main_chunk[4]; /* 'RIFF' */ u_long length; /* filelen */ char chunk_type[4]; /* 'WAVE' */ char sub_chunk[4]; /* 'fmt ' */ u_long sc_len; /* length of sub_chunk, =16 */ u_short format; /* should be 1 for PCM-code */ u_short modus; /* 1 Mono, 2 Stereo */ u_long sample_fq; /* frequence of sample */ u_long byte_p_sec; u_short byte_p_spl; /* samplesize; 1 or 2 bytes */ u_short bit_p_spl; /* 8, 12 or 16 bit */ char data_chunk[4]; /* 'data' */ u_long data_length; /* samplecount */ } WaveHeader; /* struct audio_params used to keep together audio parameters * values are as used by the /dev/dsp device */ struct audio_params { unsigned int samplerate; unsigned int afmt; unsigned int stereo; unsigned char *abuf; unsigned int size; } ; #endif siggen-2.3.10/misc.c0000600000175000017500000000637711011656464012627 0ustar jjfamily/* misc.c * Miscellaneous Functions * Jim Jackson Dec 96 */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #include #include #include #include #include #include "config.h" /* * delay(us) wait us microsecs using select. Effectively * causes current process to stop and a reschedule take place * as well as doing the delay. */ delay(us) int us; { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = us; (void)select( 1, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); } /***ERR_RPT***/ /* err_rpt(err,msg) */ err_rpt(err,msg) short int err; char *msg; { extern char *sys; if (err) fprintf(stderr,"[%s] %s : %s\n",sys,strerror(err),msg); return(err); } /***HCF***/ /* hcf(x,y) find highest common factor of x and y */ hcf(x,y) unsigned x,y; { register unsigned a,b,r; if (x>y) { a=x; b=y; } else { a=y; b=x; } for ( ; r=a%b ; a=b, b=r) { } return(b); } /***PARSE***/ /* parse(s,aa,sep) splits s up into parameters and stores ptrs * to each prm in ptr array aa (upto MAX_ARGS) * params are space or tab or 'sep' seperated, and may be * enclosed in single or double quotes e.g. 'this is 1 prm' * * returns number of parameters parsed */ parse(s,aa,sep) char *s,**aa,sep; { char *p,*q,c; int i; #define EOL ((*s=='\0') || (*s=='\n')) #define EOP ((*s==' ') || (*s=='\t') || (*s==sep)) #define QUOTE ((*s=='\'') || (*s=='"')) #define MAX_ARGS 50 for ( i=1; ; i++) { for ( ; EOP; s++) {} /* skip leading separators */ *aa++=p=s; if (EOL) return((--i)?i:1); if (i==MAX_ARGS) { return(--i); } while (!(EOL || EOP)) { if (QUOTE) { for (s++; !(EOL || QUOTE); ) *p++=*s++; if (QUOTE) s++; } else *p++=*s++; } if (EOL) {*p='\0'; return(i);} *p='\0'; ++s; } } #undef EOL #undef EOP /***mstosmaples***/ /* * mstosamples(ms,sr) convert ms millisecs into number of samples * given that the sample rate is sr samples/sec */ mstosamples(ms,sr) int ms; int sr; { int d; int m; m=INT_MAX/(4*sr); /* we need to make sure we don't overflow INT size including when no. of samples may get upped for stereo 16 bit into a byte count for getting buffers etc */ for ( d=1000; d>0 && ms>m; d/=10 ) { ms/=10; } if (d) return((sr*ms+d/2)/d); else return(0); } siggen-2.3.10/swgen.10000644000175000017500000001707311011657061012732 0ustar jjfamily.TH swgen 1 "20 Feb 1998" "Release 2.3" "Linux System Manual" .SH NAME .I swgen \- a simple swept frequency signal generator .SH SYNOPSIS .IP swgen\ [-2]\ [-s\ samples]\ [-8/-16|-b\ 8/16]\ [sweepwaveform] sweepfreq [sweptwaveform] minfreq maxfreq .IP swgen\ [-2]\ [-s\ samples]\ [-8/-16|-b\ 8/16]\ [sweepwaveform] sweepfreq [sweptwaveform] centrefreq percent% .IP waveform,\ either\ sweep\ or\ swept, is sine, cosine, square, triangle, sawtooth, noise .PP for full list of options see below. .SH DESCRIPTION .I swgen generates a swept frequency waveform on the LINUX /dev/dsp device. The swept and sweep waveform can be seperately specified, as can the sweep frequency range and the sweeping frequency. Sweep frequency range can be specified either by giving the minimum (start) and maximum (end) frequency in Hertz; or by giving the centre frequency and the percentage frequency variation below and above. The percentage is given as an integer value from 0 to 100. .PP The default sweep waveform is a sawtooth (ramp), and the default swept waveform is a sine. If the soundcard can do 16 bit samples, swgen will do 16 bit by default. .PP 8 or 16 bit samples can be generated, in mono or stereo. In stereo, one channel carries the swept frequency signal, while the second channel carries the sweeping signal. This can be useful fed to the X input of an oscilloscope when displaying frequency response curves etc. .PP The samples can be written in raw or WAV format to files instead of to the sound device. .PP The frequency is specified as an integer number of Hertz. Fractional Hertz frequencies are not supported. Of course, only frequencies less than half the samplerate (number of samples/sec) can be generated. .PP The waveforms that can be generated are: .IP sine A standard sine wave .IP cosine a sine wave with a 90 degree phase shift .IP square a standard square wave with a 50% mark space ratio .IP sawtooth a ramp waveform with 'infinitely' fast flyback (:-) An ideal oscilloscope timebase signal. .IP triangle shaped like equally spaced teeth on a saw (:-) .IP noise This is weak. All it consists of is one second of pseudo-randomly generated samples, played repeatedly. I'd love to do proper white/pink noise, but I don't know enough, and I don't think the structure of the program is conducive to accurate noise generation. .PP .I swgen creates one second's worth of generated output in a buffer and plays the buffer repeatedly, until it is terminated. .PP A lot of thought has gone into the algorithms for generating the waveforms. I believe the sin/cos wave to be very pure (modulo your sound card :-), but I don't have access to a THD meter to measure it. For best signal accuracy .I NEVER use the gain factor option (-A). The generator will then make the wave's peak value fit the maximum digital values allowed. Use a mixer program to control the output volume, or an external attenuator. .PP The gain factor option can be useful for simulating a signal that has been subject to clipping. Specify a gain of > 100%. In fact a trapezoid signal can be made by generating a clipped triangular wave. The greater the gain, the closer the signal approaches a square wave (the rise and fall times decrease). .IP Defaults output to /dev/dsp, 22050 samples/sec, mono, 16 bit samples if possible, else 8 bit. .SH OPTIONS .IP -h display usage and help info .IP -v be verbose .IP -f,-a force overwrite/append of/to file. .IP -C\ file use "file" as the local configuration file (see below). .IP -o\ file write digital sample to file ('-' is stdout) .IP -w\ file as '-o' but written as a WAVE format file. -a (append) is not valid with this option. .IP -s\ samples generate with samplerate of samples/sec .IP -8/-16\ or\ -b\ 8|16 force 8 bit or 16 bit mode. .IP -1,-2 mono (def), or special stereo mode (see above). .IP -A\ n scale samples by n/100, def. n is 100 (i.e. percentage of full scale output) .IP -t\ N|Nm generate output for either N secs or Nm millisecs only. .IP -x10\ or\ -x100 Scale frequencies down by a factor of 10 or 100. This allows fractional Hz values to be generated. See EXAMPLES below for its use. It is a Kludge. .SH EXAMPLES .IP swgen\ -v\ 2\ 100\ 1000 sweep a sin wave from 100Hz to 1000Hz using a sawtooth wave twice a second, at 22050 samples/sec, 16bit samples on 16 bit card, 8 bit samples on an 8 bit card. .IP swgen\ -v\ -s\ 44100\ -w\ sweep.wav\ 2\ 100\ 1000 as above but at a samplerate or 44100/sec and save one second of samples as a WAVE file in sweep.wav .IP swgen\ -v\ -2\ squ\ 10\ 1000\ 20% generate a sine wave switched by a 10Hz squarewave between 800Hz and 1200Hz. The swept signal is on one channel and the 10Hz square wave is on the second channel. .IP swgen\ -v\ -x10\ 5\ 4400\ 4500 generate a swept sine wave from 440Hz (4400/10) to 450Hz (4500/10), being swept at a frequency of 0.5Hz (5/10). Yes it's a royal pain remembering to scale all freqs. up by a factor of 10, but I needed it in a hurry and didn't have time to do it better. .SH CONFIGURATION\ FILES .PP Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. .PP All the siggen suite of programs are compiled with the names of the config files built in. By default the configuration files are: .IP ./.siggen.conf is the LOCAL config file. .IP $HOME/.siggen.conf is the HOME config file. .IP /etc/siggen.conf is the GLOBAL config file. .IP swgen\ -h will indicate which config files will be searched for. .PP The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. .PP The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. .PP If no configuration files exist, the program provides builtin default values, and most of these values can be set by appropriate command line switches and flags. .PP See siggen.conf(5) for details of the configuration files. .PP .I swgen looks for configuration values CHANNELS, DACFILE, SAMPLERATE, SAMPLESIZE, VERBOSE. .IP CHANNELS sets either mono or stereo mode like the '-1|-2' options. .IP DACFILE allows the name of the DAC/DSP/PCM device to be changed from /dev/dsp .IP SAMPLERATE sets the number of samples/sec for the DAC device .IP SAMPLESIZE sets whether 8 or 16 bit samples to be generated .IP VERBOSE sets whether or not to run in verbose mode. .SH .SH SEE ALSO .IP siggen.conf(5) .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/sgen.10000644000175000017500000001602411011656772012546 0ustar jjfamily.TH sgen 1 "20 Feb 1998" "Release 2.3" "Linux System Manual" .SH NAME .I sgen \- a simple signal generator program .SH SYNOPSIS .IP sgen\ [flags]\ waveform\ freq waveform is sine, cosine, square, triangle, sawtooth, noise .IP sgen\ [flags]\ pulse\ freq\ [Mark/Space] pulse has extra param Mark/Space % - def. is 10 (%) .SH DESCRIPTION .I sgen is a simple signal generator program, that can digitally generate standard waveforms on the LINUX /dev/dsp device. 8 or 16 bit samples can be generated, in mono or stereo. In stereo the two signals can be in phase or in anti-phase (180 degrees). The frequency is specified as an integer number of Hertz. Fractional Hertz frequencies are not supported. Of course, only frequencies less than half the samplerate (number of samples/sec) can be generated. .PP The waveforms that can be generated are: .IP sine A standard sine wave .IP cosine a sine wave with a 90 degree phase shift .IP square a standard square wave with a 50% mark space ratio .IP sawtooth a ramp waveform with 'infinately' fast flyback (:-) An ideal oscilloscope timebase signal. .IP triangle shaped like equally spaced teeth on a saw (:-) .IP noise This is weak. All it consists of is one second of pseudo-randomly generated samples, played repeatedly. I'd love to do proper white/pink noise, but I don't know enough, and I don't think the structure of the program is conducive to accurate noise generation. .IP pulse A square waveform where the mark/space ratio (as a percentage) can be specified. The default value is 10% (mark/space ratio of 1:9). .PP .I sgen creates one second's worth of generated output in a buffer and plays the buffer repeatedly, until it is terminated. .PP A lot of thought has gone into the algorithms for generating the waveforms. I believe the sin/cos wave to be very pure (modulo your sound card :-), but I don't have access to a THD meter to measure it. For best signal accuracy .I NEVER use the gain factor option (-A). The generator will then make the wave's peak value fit the maximum digital values allowed. Use a mixer program to control the output volume, or an external attenuator. .PP The gain factor option can be useful for simulating a signal that has been subject to clipping. Specify a gain of > 100%. In fact a trapezoid signal can be made by generating a clipped triangular wave. The greater the gain, the closer the signal approaches a square wave (the rise and fall times decrease). .IP Defaults output to /dev/dsp, 22050 samples/sec, mono, 16 bit samples if possible, else 8 bit. .SH OPTIONS .IP -h display usage and help info .IP -v be verbose .IP -o\ file write digital sample to file ('-' is stdout) .IP -w\ file as '-o' but written as a WAVE format file. -a (append) is not valid with this option. .IP -f,-a force overwrite/append of/to file. .IP -C\ file use "file" as the local configuration file (see below). .IP -s\ samples generate with samplerate of samples/sec .IP -8/-16\ or\ -b\ 8|16 force 8 bit or 16 bit mode. .IP -1,-2,-2a mono (def), stereo or stereo in antiphase .IP -A\ n scale samples by n/100, def. n is 100 (i.e. percentage of full scale output) .IP -t\ N|Nm generate output for either N secs or Nm millisecs only. .IP -x10\ or\ -x100 Scale frequencies down by a factor of 10 or 100. This allows fractional Hz values to be generated. See EXAMPLES below for its use. It is a Kludge. .SH EXAMPLES .IP sgen\ -v\ sin\ 440 generate a sin wave of 440Hz at 22050 samples/sec, 16bit samples on 16 bit card, 8 bit samples on an 8 bit card. .IP sgen\ -v\ -s\ 44100\ -w\ sin444.wav\ sin\ 440 as above but at a samplerate or 44100/sec and save a one second of samples as a WAVE file in sin440.wav .IP sgen\ -v\ -A\ 500\ saw\ 1000 generate a 1000Hz sawtooth wave severely clipped. The waveform will look like a square wave with a rise and fall time of one tenth of the wave period. (I think that's what the scribbled calculation on the back of this envelope gives :-) .IP sgen\ -v\ -2a\ sin\ 1000 generate 2 1000Hz sine waves out of phase by 180 degrees, one on each stereo channel. .IP sgen\ -v\ pulse\ 1000\ 95 generate a 1000Hz pulse wave with the 'on' period being 95% of the waveform period, i.e. a mark/space ratio of 19:1. .IP sgen\ -v\ -x10\ sin\ 2616 generate middle C 261.6Hz (2616/10) from the equally tempered scale. Yes it's a royal pain remembering to scale all freqs. by a factor of 10, but I needed it in a hurry and didn't have time to do it better. .SH CONFIGURATION\ FILES .PP Three possible configuration files can be used: a LOCAL config file (usually in current directory), a HOME config file in user's $HOME directory and a GLOBAL config file. .PP All the siggen suite of programs are compiled with the names of the config files built in. By default the configuration files are: .IP ./.siggen.conf is the LOCAL config file. .IP $HOME/.siggen.conf is the HOME config file. .IP /etc/siggen.conf is the GLOBAL config file. .IP sgen\ -h will indicate which config files will be searched for. .PP The config files do not have to exist. If they exist and are readable by the program they are used, otherwise they are simply ignored. .PP The config files are always searched for configuration values in the order LOCAL, HOME, GLOBAL. This allows a scheme where the sysadmin sets up default config values in the GLOBAL config file, but allows a user to set some or all different values in their own HOME config file, and to set yet more specific values when run from a particular directory. .PP If no configuration files exist, the program provides builtin default values, and most of these values can be set by appropriate command line switches and flags. .PP See siggen.conf(5) for details of the configuration files. .PP .I sgen looks for configuration values CHANNELS, DACFILE, SAMPLERATE, SAMPLESIZE, VERBOSE. .IP CHANNELS sets either mono or stereo mode like the '-1|-2' options. .IP DACFILE allows the name of the DAC/DSP/PCM device to be changed from /dev/dsp .IP SAMPLERATE sets the number of samples/sec for the DAC device .IP SAMPLESIZE sets whether 8 or 16 bit samples to be generated .IP VERBOSE sets whether or not to run in verbose mode. .SH .SH SEE ALSO .IP siggen.conf(5) .SH .SH BUGS .SH .SH COPYING .I Copyright\ 1995-2008\ Jim\ Jackson .PP The software described by this manual is covered by the GNU General Public License, Version 2, June 1991, issued by : .IP Free Software Foundation, Inc., .br 675 Mass Ave, .br Cambridge, MA 02139, USA .PP Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. .PP Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. .PP Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translation instead of in the original English. .SH AUTHOR .I Jim Jackson .br .sp .I Email: jj@franjam.org.uk .br siggen-2.3.10/configsubs.c0000600000175000017500000001451111011656367014025 0ustar jjfamily/* configsubs.c * functions for dealing with configuration files and returning config values * Jim Jackson Sep 98 */ /* * Copyright (C) 1998-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ /* OK what these functions do........ * * init_conf_files(local,home,global,verb) opens upto 3 configuration * files - local, home and global - that may or may not exist. * local is typically just a file in the local directory * home has the contents of the HOME env variable prepended * global is typically a system wide readable global conf. file * This function must be called before any other. If called a second * time all previous conf. files are closed automatically. * The int verb sets the verbose/debug/level. * 0 = no output, 1 = say what config files are opened/closed * 2 = also say where config values are found/matched. * Returns 0 is all ok else returns an error code. * * close_conf_files() simply closes down any open conf. files * Not really necessary, but could be useful. * * get_conf_value(sys,name,def) try and get the config. value * for parameter 'name', system 'sys', from the config. files. * config files are searched in order home, local, global. * If no specific value under system 'sys' found then any global * setting for 'name' is returned. Finally if nothing is found the * 'def' is returned. * All values are strings, as is the returned value. */ #include #include #include #define SEP ":" #define STR_SIZE 130 /* #define DEBUG(F,FP) fprintf(stderr,"%s is %s opened\n",F,(FP==NULL)?"NOT":"")*/ /* static variables for this module..... */ #define LOCAL 0 #define HOME 1 #define GLOBAL 2 #define NUM_CONF_FILES 3 #define V_OPEN(F,T,N) (verbose) && (F!=NULL) && fprintf(stderr,"%s config file %s opened.\n",T,N) #define V_CLOSE(T) (verbose) && fprintf(stderr,"Config file %s closed.\n",T) #define V_PARAM(P,V,T) (verbose>1) && fprintf(stderr,"%s : %s = %s\n",T,P,V) /* verbose enables output to stderr saying what is happenning * 0 = no output, 1 = output details of opening conf files * 2 = output where param matches are got from as well */ int verbose=0; char *Xlat(); char nm1[STR_SIZE+2]; char nm2[STR_SIZE+2]; char nm3[STR_SIZE+2]; FILE *F[NUM_CONF_FILES] = { NULL, NULL, NULL }; char *Fnm[NUM_CONF_FILES] = { nm1, nm2, nm3 }; init_conf_files(local,home,global,v) char *local,*home,*global; int v; { int st; char f[STR_SIZE+4],*p,*s; verbose=v; /* set verbose/debug level */ close_conf_files(); if (local != NULL) { F[LOCAL]=fopen(local,"r"); strncpy(Fnm[LOCAL],local,STR_SIZE); V_OPEN(F[LOCAL],"Local",local); } if (home != NULL) { s=getenv("HOME"); strncpy(f,(s!=NULL)?s:"",STR_SIZE); strcat(f,"/"); st=STR_SIZE+2-strlen(f); strncat(f,home,st); F[HOME]=fopen(f,"r"); strncpy(Fnm[HOME],f,STR_SIZE); V_OPEN(F[HOME],"Home",f); } if (global != NULL) { F[GLOBAL]=fopen(global,"r"); strncpy(Fnm[GLOBAL],global,STR_SIZE); V_OPEN(F[GLOBAL],"Global",global); } return(0); } close_conf_files() { if (F[LOCAL] != NULL) { fclose(F[LOCAL]); F[LOCAL]=NULL; V_CLOSE(Fnm[LOCAL]); } if (F[HOME] != NULL) { fclose(F[HOME]); F[HOME]=NULL; V_CLOSE(Fnm[HOME]); } if (F[GLOBAL] != NULL) { fclose(F[GLOBAL]); F[GLOBAL]=NULL; V_CLOSE(Fnm[GLOBAL]); } } char *get_conf_value(sys,name,def) char *sys,*name,*def; { int st,i,n; char f[STR_SIZE+4],*p,*s; *f=0; n=0; if (name == NULL || *name == 0) return(def); if (sys != NULL) { strncpy(f,sys,STR_SIZE); strcat(f,SEP); n=strlen(f); } s=f+n; strncat(s,name,STR_SIZE+2-n); /* ok here we have f[]=sysSEPname (if sys exists) * and s points to the name part of the buffer * First we search the config files in local, home, global order * for any specific sysSEPname match, returning if anything found. * If no match and sys specified then just search for name. * If still no match return default def value * This allows simple global defaults to be set with specific * exceptions by using the sys name etc */ for (i=0; i*/ #include /* CONFIGURATION OPTION - either here or in your make file * I like the 'open field' functioning - others may not. * Simply uncomment the define here for 'closed' fields */ /*#define CLOSED_FIELDS */ /* Some misc. defines......... */ #define RANGE(L,X,U) ((X<=L)?L:((X>=U)?U:X)) #define MAXINTWIDTH 9 static int POWERS10[]= { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0 }; #define LIMITS(N) (POWERS10[N]-1) #define MAXCOL 256 /* ==================================================================== * Functions calls where everything is passed as separate parameters */ /* macro function calls....... */ #define mvactfint(L,C,K,A,IP,W,O) ((move(L,C)==ERR)?ERR:actfrac(K,A,IP,W,O,0)) #define mvputfint(L,C,A,N,W) ((move(L,C)==ERR)?ERR:putfrac(A,N,W,0)) #define mvactfrac(L,C,K,A,IP,W,O,DP) ((move(L,C)==ERR)?ERR:actfrac(K,A,IP,W,O,DP)) #define mvputfrac(L,C,A,N,W,DP) ((move(L,C)==ERR)?ERR:putfrac(A,N,W,DP)) #define mvactfstr(L,C,K,A,P,PP,W) ((move(L,C)==ERR)?ERR:actfstr(K,A,P,PP,W)) #define mvputfstr(L,C,A,P,W) ((move(L,C)==ERR)?ERR:putfstr(A,P,W)) #define actfint(K,A,IP,W,O) actfrac(K,A,IP,W,O,0) #define putfint(A,N,W) putfrac(A,N,W,0) #define putfopt(A,S,I,W) putfstr(A,S[I],W) #define mvactfopt(L,C,K,A,P,I,W) ((move(L,C)==ERR)?ERR:actfopt(K,A,P,I,W)) #define mvputfopt(L,C,A,P,I,W) ((move(L,C)==ERR)?ERR:putfstr(A,P[I],W)) /* Main io field structure definition ....... */ struct SCField { /* WINDOW *win; */ /* Window this field is in */ int type; /* type of field - see below */ int row; /* row and col of start of field */ int col; int attr; /* attribute to use for field */ union { void *tp; /* general void ptr */ char *s; /* or pointer to string */ char **sp; /* or a ptr to an array of options */ int *i; /* integer value of field - see below */ float *f; /* or float value */ } val; int W; /* width in chars of field */ int adj; /* a 2nd parameter for some fields */ int id; /* field identifier for e.g. tying fields together or any special application use */ int dp; /* In integer/fractions number of dec. places */ }; /* values for the type field define the type of value defined * and some simple attributes of the value * * integer - is a cash till type integer entry. Cursor stays fixed on right * fraction - is a fixed decimal point fractional value. * string - simple string value * option - allows one of a fixed set of values to be choosen */ #define SCF_type 0xff #define SCF_integer 1 /* A Fraction with dp == 0 ! */ #define SCF_fraction 1 #define SCF_string 2 #define SCF_real 3 /* NOT YET IMPLEMENTED */ #define SCF_option 4 #define SCF_fixed 0x100 /* field has a fixed value - cannot be altered */ /* default is NOT fixed */ #define SCF_justify 0x200 /* field is justified opposite to default */ /* string right justified, int and real left*/ #define SCF_overwrite 0x400 /* data entered into field does not insert */ /* but overwites existing data */ /* macros acting on SCField.type field flags above. These macros act on * the given SCF_type and return the new value of the SCF_type. * * - test SCField type to see if field is not fixed, i.e. an input field * - to force field to be fixed * - to make field an input field, i.e. remove the fixed value * - to put field in overwrite mode * - to put field in insert mode (default condition) */ #define CAN_INPUT(T) (!((T) & SCF_fixed)) #define INSERTING(T) (!((T) & SCF_overwrite)) #define FIXED_FIELD(T) ((T) | SCF_fixed) #define INPUT_FIELD(T) ((T) & (~SCF_fixed)) #define OVERWRITE_FIELD(T) ((T) | SCF_overwrite) #define INSERT_FIELD(T) ((T) & (~SCF_overwrite)) /* These macros take a struct SCField * and manipulate it's contents * as if they were functions. For all those that change SCF_type field * the returned value is the new value of the field. */ /* these interrogate the structure and return values... * First these check true or false.... */ #define CanInput(S) (CAN_INPUT(S->type)) #define Inserting(S) (INSERTING(S->type)) #define IsFieldInt(S) ((((S->type)&SCF_type) == SCF_integer) && ((S->dp)==0)) #define IsFieldFrac(S) ((((S->type)&SCF_type) == SCF_integer) && (S->dp)) #define IsFieldStr(S) (((S->type)&SCF_type) == SCF_string) #define IsFieldOption(S) (((S->type)&SCF_type) == SCF_option) /* These set values in the field structure........ */ #define FixedField(S) (S->type = FIXED_FIELD(S->type)) #define InputField(S) (S->type = INPUT_FIELD(S->type)) #define OverwriteField(S) (S->type = OVERWRITE_FIELD(S->type)) #define InsertField(S) (S->type = INSERT_FIELD(S->type)) #define SetAttrib(S,A) (S->attr = A) #define SetWidth(S,WIDTH) (S->W = WIDTH) #define SetDP(S,D) (S->dp = D) #define SetOffset(S,O) (S->adj = O) #define SetOptionIndex(S,O) (S->adj = O) #define SetInt(S,I) (*(S->val.i) = I) #define SetStr(S,ST) ((S->val.s) = ST) #define SetOption(S,OP) ((S->val.sp) = OP) /* These return values from the field structure....... */ #define GetType(SP) ((SP->type)&SCF_type) #define GetInt(SP) (*(SP->val.i)) #define GetStr(SP) (SP->val.s) #define GetOption(SP) ((SP->val.sp)[SP->adj]) #define GetOptionIndex(SP) (SP->adj) #define GetFrac(SP) (((double)*(SP->val.i))/(double)POWERS10[RANGE(0,SP->dp,MAXINTWIDTH)]) #define GetOffset(S) (S->adj) #define GetDP(S) (S->dp) #define GetAttrib(S) (S->attr) #define GetWidth(S) (S->W) /* ==================================================================== * Function calls where everything is passed thru' a structure */ struct SCField *newfield(int type,int att,int COL,int ROW, int W,void *D,int id,int dp); int actfield(int k, struct SCField *F); int putfield(struct SCField *F); struct SCField *dupfield(struct SCField *F); /* ====================================================================== */ #ifndef CLOSED_FIELDS # define OPEN_FIELDS #endif #endif /* __SCFIO_H */ siggen-2.3.10/scrsubs.c0000600000175000017500000001316111011656515013342 0ustar jjfamily/* scrsubs.c * Screen handling routines using scfio and ncurses * Jim Jackson Oct 98 */ /* * Copyright (C) 1997-2008 Jim Jackson jj@franjam.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 - see the file COPYING; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. */ #include #include #include #include #include "scfio.h" #include "config.h" extern int vikeys; /* * doinput(c,aa,H,f) action char c on field aa[f] * if field changes display old field in normal and new * field in reverse, and display relevant new help line from H[] * return new field value. */ doinput(c,aa,H,HF,f) int c; struct SCField *aa[]; char *H[]; struct SCField *HF; int f; { int fn,i; if ((c&0x7F)==12) { /* redraw screen '^L' */ touchwin(stdscr); wrefresh(curscr); return(f); } if (vikeys) { if (c=='h' || c=='H') c=KEY_LEFT; else if (c=='j' || c=='J') c=KEY_UP; else if (c=='k' || c=='K') c=KEY_DOWN; else if (c=='l' || c=='L') c=KEY_RIGHT; } c=actfield(c,aa[f]); fn=-1; if (strchr(UNLOCK_FIELD_CHARS,c)!=NULL) { for (i=0; aa[i]!=NULL; i++) { if (!(CanInput(aa[i]))) { aa[i]->attr=reverse_attr(aa[i]->attr); putfield(aa[i]); InputField(aa[i]); } } putfield(aa[f]); } else if (strchr(LOCK_FIELD_CHARS,c)!=NULL) { fn=next_field(aa,f); if (fn!=f) { FixedField(aa[f]); aa[f]->attr=reverse_attr(aa[f]->attr); } } else if (c==KEY_LEFT) { fn=prev_field(aa,f); } else if (c==KEY_RIGHT || c=='\r' || c=='\n' || c=='\t') { fn=next_field(aa,f); } else if (c==KEY_HOME) { fn=0; } if (fn!=-1) { dispfield(aa,H,HF,f); f=fn; dispfield(aa,H,HF,f); } refresh(); return(f); } /* dispfield(ff,hh,HF,f) display SCField ff[f] along with associated * help line hh[f] on info line. */ dispfield(ff,hh,HF,f) struct SCField *ff[]; char *hh[]; struct SCField *HF; int f; { doinfo(hh[f],0,HF); ff[f]->attr=reverse_attr(ff[f]->attr); putfield(ff[f]); } /* prev_field(aa,n) find previous field to field n */ int prev_field(aa,n) struct SCField *aa[]; int n; { int i,fn; for ( i=n; ; i=fn ) { if (i) fn=i-1; else { for (fn=i ; aa[fn+1]!=NULL; fn++) { } } if (CanInput(aa[fn]) || fn==n) break; } return(fn); } /* next_field(aa,n) find next field to field n * if n is -1 find first field */ int next_field(aa,n) struct SCField *aa[]; int n; { int i,fn; for ( i=n ; ; i=fn ) { fn=i+1; if (aa[fn]==NULL) fn=0; if (CanInput(aa[fn]) || fn==n) break; } return(fn); } /* setwaveform(sp,wv,WFS) */ setwaveform(sp,wv,WFS) struct SCField *sp; char *wv; char *WFS[]; { int i,n; n=strlen(wv); for (sp->adj=i=0; WFS[i]!=NULL; i++) { if (strncasecmp(wv,WFS[i],n)==0) { sp->adj=i; return(0); } } } /* dohdr(y,a1,a2,a3,h1,h2,S,V) write header out starting at line y using * attributes a1, a2, and a3. Header lines are in arrays h1[] and h2[] * S is sig line and V is version line at bottom of screen. */ dohdr(y,a1,a2,a3,h1,h2,S,V) int y,a1,a2,a3; char *h1[],*h2[],*S,*V; { int i; for ( i=0; h1[i]!=NULL; i++) { mvputfstr(y+i,0,a1,h1[i],80); } for ( i=0; h2[i]!=NULL; i++) { mvputfstr(y+i+1,55,a2,h2[i],17); } mvputfstr(y+6,44,a3,S,strlen(S)); mvputfstr(LINES-2,0,a3," ",80); mvputfstr(LINES-1,0,a1,V,80); } /* Display string s in the Info field of the screen, and pause for w * seconds, if w is non-zero */ doinfo(s,w,SF) char *s; int w; struct SCField *SF; { SF->val.s=s; putfield(SF); refresh(); if (w) sleep(w); } /* dotime(F) gettimeofday and display */ dotime(F) struct SCField *F; { int y,x; time_t t; struct tm *BT; t=time(NULL); BT=localtime(&t); sprintf(F->val.s,"%2d:%02d:%02d",BT->tm_hour,BT->tm_min,BT->tm_sec); getyx(stdscr,y,x); putfield(F); move(y,x); refresh(); } dofields(aa) struct SCField *aa[]; { int i; for (i=0; aa[i]!=NULL; i++) { putfield(aa[i]); } } dofatt(aa,at) struct SCField *aa[]; int at; { int i; for (i=0; aa[i]!=NULL; i++) { aa[i]->attr=at; } } mergefields(aa1,aa2) struct SCField *aa1[],*aa2[]; { int i,j; for (i=0; aa1[i]!=NULL; i++) { } for (j=0; aa2[j]!=NULL; i++,j++) { aa1[i]=aa2[j]; } aa1[i]=aa2[j]; /* copy the terminating null */ } /* scfeql(f1,f2) make f1 contain the same value as field f2 * if int/frac make dp's same, integer same, and offset * if string make string value same and offset * if option make option value same */ scfeql(f1,f2) struct SCField *f1,*f2; { if (GetType(f1)!=GetType(f2)) return(1); if (GetType(f2)==SCF_integer) { SetInt(f1,GetInt(f2)); SetOffset(f1,GetOffset(f2)); SetDP(f1,GetDP(f2)); } else if (IsFieldStr(f2)) { SetOffset(f1,GetOffset(f2)); strncpy(GetStr(f1),GetStr(f2),GetWidth(f1)); } else if (IsFieldOption(f2)) { SetOptionIndex(f1,GetOptionIndex(f2)); } } siggen-2.3.10/VERSION.2.3.100000600000175000017500000000000011011657262013266 0ustar jjfamilysiggen-2.3.10/siggen.aft0000600000175000017500000001464011011653437013465 0ustar jjfamily*Title: Signal Generation tools for Linux and /dev/dsp *Author: Jim Jackson _SIGGEN_ _Release 2.3.10 As with all software: there just maybe bugs_ *What are the programs? This is a set of tools for imitating a laboratory Signal Generator, generating audio signals out of Linux's /dev/dsp audio device. There is support for mono and/or stereo and 8 or 16 bit samples. The basic waveform sample generation code is in the file generator.c, the functions here can be added to other programs fairly easily. The current version can be downloaded from here {+http://www.comp.leeds.ac.uk/jj/linux/siggen.tgz+}. This is a bug fix release. _2.3.10_ Release: Paul Martin & Jens Peter Secher (Debian siggen package maintainer), reported problems with swept waveforms. There was an integer overflow problem in some circumstances - usually when using the x10 or x100 options. Also this release changes the config file name from the old _sound.conf_ to _siggen.conf_ . Users with existing files can do: ^<< cd ~ ln -s .sound.conf siggen.conf as root cd /etc ln -s sound.conf siggen.conf or simply copy the files ^>> There should also be less warnings now! _2.3.9_ Release: Lukas Loehrer reported a problem with writing raw sound files, and Mark Shimonek reported a bug and fix with setting the DSP device. Several of the programs below are front ends for using the generator functions, mixing the generated outputs and playing them on /dev/dsp. None of the generation programs control the mixer - use your favourite mixer program or use the simple mixer 'smix' which I have included here. #_soundinfo_ A program to display some of the programming capabilities of the sound system support for the mixer device /dev/mixer and the DSP device /dev/dsp. Can easily be changed if the mixer and dsp devices are called something else. Also shows some of the ioctl calls in action :-).\\ Further info on your kernel's sound card configuration is given by 'cat /dev/sndstat'. #_sgen_ is a command line signal generator where details are specified from the command line for generating sine, cos, square, triangle, sawtooth, pulse, noise waves. Frequency, sample rate, relative amplitude etc can be specified thru' command line options. The signal is played continuously until the program is stopped. There are options to save the basic raw digital samples raw to file or to a WAVE format file. #_swgen_ is a command line sweep generator. Both the sweeping and swept waveforms can be specified, along with the sweeping frequency and the swept frequency range. Otherwise similar to sgen above. #_siggen_ an Ncurses screen based Signal Generator for 2 seperate channels. On stereo audio cards the 2 channels are played on seperate outputs. On mono cards the 2 channels are digitally mixed onto the one output. Type of waveform, frequency, amplitude, sample rate etc are specified/changed via a screen menu. This is version 2. It plays continuously. Changes to parameters take effect (nearly) immediately. This version is pretty CPU intensive. #_sweepgen_ an Ncurses screen based Sweep generator (see swgen above). It is like siggen. Changes to parameters take effect (nearly) immediately. #_tones_ a command line program to generate several successive tones of varying freq., and optional differing waveforms, durations and intensities.\\ The sequence of tones can be either played once (the default), or repetitively or the samples can be written to a file in raw or WAV format. This could make the basis of an auto-dialer for tone phones.\\ Check out README.tones and the tones.eg directory for some examples of using the tones program. #_smix_ a simple command line program for getting and setting the mixer settings. (Eee by gum, yet another mixer, yawn). #_fsynth_ an Ncurses based "fourier" synthesis "realtime" generator. *Compiling and installing You will need the ncurses library and header files. You will need sound card support compiled into your kernel. You can build some of the programs, tones sgen and swgen, without soundcard support. These programs then can be used to generate raw data or WAV files. You can also compile these programs under other OSes than Linux, e.g. Sunos 4.1. Edit the configuration file config.h, to set the options/defaults you require. The defaults assume compilation under Linux with soundcard support. The file has ample comments and should be self explanatory. If anyone wants to suggest changes for building under other OSes then let me know and I'll inlcude the changes. Check out the Makefile and edit anything that is wrong for your system. The ncurses library is assumed to be in normal library 'path' and the ncurses include file is assumed to be in either /usr/include/curses or /usr/include/ncurses/curses . If not, edit as appropriate. Just type 'make' to make the programs. Don't set -Wall in the makefile, the results will be deeply embarassing to yours truly :-) All the programs support optional interrogation of a common set of configuration files. See _CONFIG.FILES_ for details. Type 'make sysinstall' to install the programs into /usr/local/bin and the man pages into /usr/local/man/man1. Type 'make localinstall' to install into $HOME/bin and $HOME/man/man1. If none of these are ok for you then copy manually or edit the Makefile. Edit the setting of variable PROGS to customise which programs you install, e.g. you may not wish to install yet another mixer program so delete smix from the list. These programs have been tested on on various versions of Linux from Kernels 2.0.36 - 2.6.22, and on distributions from RedHat et al., Debian and Ubuntu. Seems to work with ALSA or OSS, and I have reports of it porting to FreeBSD easily. Compiled with no sound card support, the command line utilities should work for creating sound files on most *nix OSes. *Distribution and Copying Distribution of this package is covered by the terms of the GNU General Public License, version 2. See the file COPYING for further details. These programs are Copyright (c) 1996-2008 Jim Jackson & contributors. Jim Jackson -------------------- HomePage {+http://www.comp.leeds.ac.uk/jj+}