/* play -- Dump a soundfile to the DAC (/dev/ai0) * * Revisions: * 1.2 12/17/87 -- Fixed buffer flushing, added timeouts * 1.1 12/16/87 -- Basic play by bgg, dressed-up by jwp * (error handling, signal traps, multiple files) * 1.3 5/88 -- forking process to handle new driver, smaller * DMA buffers, carriage return to start -- bgg */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aireg.h" #include "aivar.h" #include #include #include "sfheader.h" #include #define TRUE 1 #define FALSE 0 #define ABS(x) ( (x < 0) ? -(x) : (x) ) #define CLOCK1 14400000 #define CLOCK2 14318180 int devfd; /* fd for DAC device */ struct aud_conv stuff; /* info for driver */ main(argc,argv) int argc; char **argv; { int sffd; short csr_stat; struct stat sfst; SFHEADER hd; void byebye(),getinfo(),calcskip(); int build_srint(); extern int errno; extern char *optarg; extern int optind; int o,badopt = 0; int i; float durtime,skiptime,srate; float atof(); int skipbytes,durbytes,nchannels; int skipflag = 0; int durflag = 0; int noheader = 0; int srflag = 0; int id,status; char dummy; /* Parse some options: */ while ((o = getopt(argc,argv,"d:s:r:n")) != EOF) { switch(o) { case 'd': durtime = atof(optarg); fprintf(stderr,"play duration set to %.2f seconds\n",durtime); durflag = 1; break; case 's': skiptime = atof(optarg); fprintf(stderr,"skipping %.2f seconds\n",skiptime); skipflag = 1; break; case 'r': srate = atof(optarg); fprintf(stderr,"sampling rate set to %f\n",srate); srflag = 1; break; case 'n': getinfo(&srate,&nchannels); noheader = 1; break; default: badopt++; break; } } if (argc == optind || badopt) faterr("Usage: play [-s SKIP -d DUR -r [S. RATE] -n ] soundfile ..."); /* Trap some signals */ signal(SIGHUP,byebye); signal(SIGINT,byebye); signal(SIGQUIT,byebye); signal(SIGBUS,byebye); signal(SIGSEGV,byebye); signal(SIGTERM,byebye); signal(SIGTSTP,SIG_IGN); /* Play some soundfiles */ while ((i = optind++) < argc) { /* Open up the converter and soundfile */ if ((devfd = open("/dev/ai0",0,2)) < 0) faterr("Can't open converter device"); if ((sffd = open(argv[i],0,2)) < 0) { fprintf(stderr,"Can't open soundfile: %s\n",argv[i]); return(-1); } if (!noheader) { /* Be sure this is a soundfile, and that it has short samples, not floats. */ if (rheader(sffd,&hd)) { fprintf(stderr,"Can't read sfheader\n"); close(sffd); return(-1); } close(sffd); if (!ismagic(&hd)) { fprintf(stderr,"%s: not a soundfile\n",argv[i]); return(-1); } if (sfclass(&hd) != SF_SHORT) { fprintf(stderr,"%s: not 'short' samples\n",argv[i]); return(-1); } if (!srflag) srate = (float)sfsrate(&hd); nchannels = sfchans(&hd); sffd = open(argv[i],0,2); } fstat(sffd,&sfst); stuff.a_bufskip = 0; /* no buffers skipped */ stuff.a_byteskip = 0; /* leave this if no header */ if (!noheader) stuff.a_byteskip = 1024; /* skip the header */ if (skipflag) { skipbytes = (int)skiptime*(int)srate*nchannels*2; if (!noheader) skipbytes += 1024; calcskip(skipbytes); if (skipbytes > sfst.st_size) { fprintf(stderr,"skip of %.2f is longer than the file!\n",skiptime); exit(-1); } } if (durflag) { durbytes = (int)durtime*(int)srate*nchannels*2; durbytes += skipbytes; if ( !noheader & (skipbytes == 0) ) durbytes += 1024; if (durbytes > sfst.st_size) fprintf(stderr,"duration is longer than the file, will do the whole thing\n"); else sfst.st_size = durbytes; } /* Set up info for the converter */ stuff.a_nbytes = sfst.st_size; /* number of bytes in file */ stuff.a_fd = sffd; /* file descriptor */ stuff.a_flags = 0; stuff.a_numdbs = 2; stuff.a_nchans = nchannels; stuff.a_srate = build_srint(srate,nchannels); stuff.a_scanflag = 0x00000000; /* for timeout */ /* Initialize converter */ if (ioctl(devfd,AIO_SET_DAC,&stuff) < 0) { fprintf(stderr,"Can't set DAC (errno = %d)",errno); fprintf(stderr," -- try again\n"); ioctl(devfd,AIO_RESET,&stuff); close(devfd); exit(-1); } /* pause for carriage return */ printf(" to play "); scanf("%c",&dummy); /* Play this file */ if ( (id = fork() ) == 0 ) { /* child does the playing */ signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); signal(SIGBUS,SIG_IGN); signal(SIGSEGV,SIG_IGN); signal(SIGTERM,SIG_IGN); signal(SIGTSTP,SIG_IGN); if (ioctl(devfd,AIO_GO,&stuff) < 0) { fprintf(stderr,"Error on conversion (errno = %d) ",errno); fprintf(stderr,"-- try again\n"); ioctl(devfd,AIO_RESET,&stuff); close(devfd); exit(-1); } } wait(&status); if (status == -1) return(-1); close(devfd); sleep(1); /* wait a sec before going to next file */ } } void byebye(sig) int sig; { fprintf(stderr,"\nplay terminated (signal %d)\n",sig); if (sig == SIGINT) { signal(SIGINT,SIG_IGN); } ioctl(devfd,AIO_STOP,&stuff); sleep(2); /* wait for dac to flush */ close(devfd); exit(0); } faterr(msg) char *msg; { fprintf(stderr,"%s\n",msg); close(devfd); exit(1); } void getinfo(sr,nch) float *sr; int *nch; { printf("enter sampling rate: "); scanf("%f",sr); printf("enter number of channels: "); scanf("%d",nch); } void calcskip(skip) int skip; { int skipbufs,skipchars; skipbufs = skip/8192; if (skipbufs > 0) skipchars = skip % (skipbufs * 8192); else skipchars = skip; stuff.a_bufskip = skipbufs; stuff.a_byteskip = skipchars; } /* convert sampling rate to ds16 lo and hi SR register format */ build_srint(desired,nchans) float desired; int nchans; { float basis1,basis2,fbase1,fbase2,basis; int ibase1,ibase2,ibasis,result,tbase = 0; short lo,hi,tophi; char *byter; basis1 = CLOCK1/desired; basis2 = CLOCK2/desired; ibase1 = basis1; ibase2 = basis2; fbase1 = basis1 - (float)ibase1; fbase2 = basis2 - (float)ibase2; if (ibase1 > 4096) { if (ibase2 > 4096) { fprintf(stderr,"sampling rate too low\n"); exit(-1); } else { tbase = CLOCK2; basis = basis2; } } else { if (ibase2 > 4096) { tbase = CLOCK1; basis = basis1; } } if (tbase == 0) { if (fbase1 < fbase2) { if ( ABS(fbase2 - .99999) < fbase1 ) { tbase = CLOCK2; basis = basis2; } else { tbase = CLOCK1; basis = basis1; } } else { if ( ABS(fbase1 - .99999) < fbase2 ) { tbase = CLOCK1; basis = basis1; } else { tbase = CLOCK2; basis = basis2; } } } ibasis = basis; if ( (basis - (float)ibasis) > 0.5 ) basis += 1.0; ibasis = basis; result = 4096 - ibasis; if (result < 0) { fprintf(stderr,"bad SR selection, result = %d\n",result); exit(-1); } byter = (char *)&result; byter += 2; hi = (*byter & 0x00ff) | ( (*byter << 8) & 0xff00 ); byter += 1; lo = (*byter & 0x00ff) | ( (*byter << 8) & 0xff00 ); tophi = 0x0000; if ( (int)desired*nchans > 50000 ) tophi = 0x4040; if (tbase == CLOCK2) tophi = tophi | 0x1010; hi = hi | tophi; result = (lo & 0x0000ffff) | ( (hi << 16) & 0xffff0000 ); return(result); }