/**************************************************************************** * VOCALIZER: A speech articulation program * * Copyright John A. Magliacane, KD2BD 1999-2003 * * Last update: 02-Mar-2003 * ***************************************************************************** * This program is used by PREDICT to annunciate satellite coordinates * * through the system's soundcard (/dev/dsp) using .wav files containing * * uncompressed "raw" PCM data. It is called as a background process. * ***************************************************************************** * * * 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 any later * * version. * * * * This program is distributed in the hope that it will 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. * * * *****************************************************************************/ #include #include #include #include #include #include #include #include "vocalizer.h" int dsp; char numstr[20][10]; unsigned char buffer[65536]; unsigned long buffer2long(indx) int indx; { unsigned long byte0, byte1, byte2, byte3; if ((indx+3)<65536) { byte0=(unsigned long)buffer[indx]; byte1=(unsigned long)buffer[indx+1]; byte2=(unsigned long)buffer[indx+2]; byte3=(unsigned long)buffer[indx+3]; return (byte0|(byte1<<8)|(byte2<<16)|(byte3<<24)); } else return 0L; } unsigned int buffer2int(indx) int indx; { unsigned int byte0, byte1; if ((indx+1)<65536) { byte0=(unsigned int)buffer[indx]; byte1=(unsigned int)buffer[indx+1]; return (byte0|(byte1<<8)); } else return 0; } int wavplay(filename) char *filename; { int x, y, format, bits, bytes, channels, block_size, dsp, fd; unsigned long total_samples=0L, rate=0L, running_total=0L; char filenpath[80]; strncpy(filenpath,path,79); strncat(filenpath,filename,79); strncat(filenpath,".wav",79); fd=open(filenpath,O_RDONLY); if (fd==-1) { fprintf(stderr,"*** vocalizer: Cannot open \"%s\"\n",filenpath); return -1; } bytes=read(fd,&buffer,65536); y=((buffer[0]^'R') | (buffer[1]^'I') | (buffer[2]^'F') | (buffer[3]^'F') | (buffer[8]^'W') | (buffer[9]^'A') | (buffer[10]^'V') | (buffer[11]^'E')); if (y) { fprintf(stderr,"*** vocalizer: No RIFF header found!\n"); return -1; } for (x=12, y=1; x<65535 && y; x++) y=((buffer[x]^'f') | (buffer[x+1]^'m') | (buffer[x+2]^'t') | (buffer[x+3]^' ')); if (y==0) { x+=3; x+=4; format=buffer2int(x); x+=2; channels=buffer2int(x); x+=2; rate=buffer2long(x); x+=4; x+=4; block_size=buffer2int(x); x+=2; bits=buffer2int(x); x+=2; if (format!=1) { fprintf(stderr,"*** vocalizer: Not PCM Wave Format.\n"); return -1; } for (x=0, y=1; x<65535 && y; x++) y=((buffer[x]^'d') | (buffer[x+1]^'a') | (buffer[x+2]^'t') | (buffer[x+3]^'a')); if (y==0) { x+=3; total_samples=buffer2long(x); if (total_samples!=0L) { dsp=open("/dev/dsp",O_RDWR); if (dsp==-1) { fprintf(stderr,"*** vocalizer: Cannot open /dev/dsp!\n"); return -1; } ioctl(dsp,SOUND_PCM_WRITE_CHANNELS,&channels); ioctl(dsp,SOUND_PCM_WRITE_RATE,&rate); ioctl(dsp,SOUND_PCM_WRITE_BITS,&bits); lseek(fd,(long)(x+4),SEEK_SET); bytes=read(fd,&buffer,65536); running_total+=bytes; if (running_total>total_samples) bytes-=(running_total-total_samples); while (bytes>0) { write(dsp,&buffer,bytes); bytes=read(fd,&buffer,65536); running_total+=bytes; if (running_total>total_samples) bytes-=(running_total-total_samples); } close(dsp); close(fd); } } else fprintf(stderr,"*** vocalizer: Could not find 'data' chunk.\n"); } else fprintf(stderr,"*** vocalizer: Could not extract format from header.\n"); return 0; } void saynumber(num) int num; { char string[10]; sprintf(string,"%4d",num); if (string[1]!=32) { wavplay(numstr[string[1]-48]); wavplay("hundred"); } switch (string[2]) { case '1': wavplay(numstr[(10+(string[3]-48))]); break; case '2': wavplay("twenty"); break; case '3': wavplay("thirty"); break; case '4': wavplay("forty"); break; case '5': wavplay("fifty"); break; case '6': wavplay("sixty"); break; case '7': wavplay("seventy"); break; case '8': wavplay("eighty"); break; case '9': wavplay("ninety"); break; } if (string[3]!=32 && string[3]!=0 && string[2]!='1' && string[3]!='0') wavplay(numstr[string[3]-48]); if (string[3]=='0' && string[2]==32 && string[1]==32) wavplay("zero"); } int main(argc,argv) int argc; char *argv[]; { int number; strcpy(numstr[1], "one\0"); strcpy(numstr[2], "two\0"); strcpy(numstr[3], "three\0"); strcpy(numstr[4], "four\0"); strcpy(numstr[5], "five\0"); strcpy(numstr[6], "six\0"); strcpy(numstr[7], "seven\0"); strcpy(numstr[8], "eight\0"); strcpy(numstr[9], "nine\0"); strcpy(numstr[0], "zero\0"); strcpy(numstr[10],"ten\0"); strcpy(numstr[11],"eleven\0"); strcpy(numstr[12],"twelve\0"); strcpy(numstr[13],"thirteen\0"); strcpy(numstr[14],"fourteen\0"); strcpy(numstr[15],"fifteen\0"); strcpy(numstr[16],"sixteen\0"); strcpy(numstr[17],"seventeen\0"); strcpy(numstr[18],"eighteen\0"); strcpy(numstr[19],"nineteen\0"); /* Start talking! */ if (argc==2) { if (strncmp(argv[1],"eclipse",7)==0) { wavplay("alarm"); wavplay("eclipse"); } if (strncmp(argv[1],"sunlight",8)==0) { wavplay("alarm"); wavplay("sunlight"); } if (strncmp(argv[1],"los",3)==0) wavplay("los"); } if (argc>=3) { wavplay("intro"); number=atoi(argv[1]); saynumber(number); wavplay("azimuth"); number=atoi(argv[2]); saynumber(number); wavplay("elevation"); if (argc>=4) { if (argv[3][0]=='+') wavplay("approaching"); if (argv[3][0]=='-') wavplay("receding"); } if (argc==5) { if (argv[4][0]=='V') wavplay("visible"); } } return 0; }