This is saystring.c in view mode; [Download] [Up]
/* saystring.c [version 0.8 for NeXT Release 2.1] * A command line program to speak a text string through NeXT audio out. * * This is essentially a program that plays concatenated sound files of words with * some special treatment for numbers. As such, it only can speak words that have * corresponding sound files. Numbers are spoken by concatenating digit sounds. * The program is very simple and low overhead, but should be quite usable for * applications that needs only limited vocaburary. This has been written to * provide voice alerts for monitoring experimental parameters in a biology lab. * (Commands come from remote devices via rsh.) * * Usage: saystring "A line to be spoken" * Example: saystring "temperature #39.4 degrees is too_high" * Example: saystring "our phone number is #6 #4 #2 _ #6 #4 #4 #0" * * You must prepare sound files yourself for numbers and any other words you use. * Sound files should be in /usr/local/lib/saystring_sounds directory, but can be changed * by SOUNDDIR define below and recompiling. All sound files currently have to * be in CODEC (8-bit mu-law, ~8kHz sampling) format, but this can be changed as well. * * To compile: cc -Wall -o saystring saystring.c * will work. You can use strip, or other options to make the executable smaller. * * This program is in the Public Domain. Do anything you want with it. * * Version 0.8 * 92-08-22 Izumi Ohzawa * This is a sloppy one-night hack. Only good for single shot uses (Program should * terminate for each use) because memory deallocation is pretty much ingnored. * Fix malloc/free if you want to incorporate into a long running app as a subroutine. * Only handles floats and integers in the range of +/- 9999.9999999... * It should not be hard to extend it if you want to. */ #import <stdio.h> #import <string.h> /* for strlen, rindex, etc */ #import <stdlib.h> #import <sys/param.h> #import <sound/sound.h> /* Change this if you want a different directory to store sound files */ #define SOUNDDIR "/usr/local/lib/saystring_sounds" #define TAG 1 #define MAXWORDS 200 /*==== Global Vars for sloppy programming ===================================================== */ /* You must prepare the following *.snd files for numbers to be spoken correctly. * In addition, you will need sound files for: "minus", "point", "thousand", "hundred". */ char *dig09[] = {"zero","one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; char *teens[] = {"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; char *tens[] = {"", "ten","twenty","thirty","forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; char *word[MAXWORDS]; int nwords = 0; char *p; char buf[128]; void do_number(void) { int minus = 0; /* non-zero if negative */ int isfrac = 0; /* non-zero if there is a decimal point */ int ipart, temp, saveipart; char ch[2]; char *frac; ch[1] =0; sscanf(p, "%s", buf); /* get the number into string */ if(strlen(buf) == 0) return; if(atof(buf) < 0.0) /* say "minus" first ? */ { minus = 1; /* indicate negative */ word[nwords++] = "minus"; } if((frac = index(buf, '.'))) /* Do we have a decimal point? */ { *frac = '\0'; /* replace decimal pt with null char */ frac++; /* fraction part */ if(strlen(frac)) /* if there is anything after '.', it is a float # */ isfrac =1; } ipart = atoi(buf); /* integer part. buf==NULL if e.g. #.123, which is OK */ if(ipart < 0) ipart = -ipart; /* make positive */ if(ipart > 9999) ipart = 9999; /* Our current implementation limit */ saveipart = ipart; /* save a copy for 0 */ /* do thousands */ if((temp = ipart/1000)) { word[nwords++] = dig09[temp]; word[nwords++] = "thousand"; } /* hundreds */ ipart -= temp *1000; /* get rid of thousands */ if((temp = ipart/100)) { word[nwords++] = dig09[temp]; word[nwords++] = "hundred"; } /* tens */ ipart -= temp *100; /* get rid of hundreds */ if((temp = ipart/10)) { if(temp ==1) /* teens */ { word[nwords++] = teens[ipart-10]; goto do_fraction; } else word[nwords++] = tens[temp]; } /* ones */ ipart -= temp*10; /* get rid of tens */ if(ipart || saveipart == 0) word[nwords++] = dig09[ipart]; do_fraction: if(isfrac) /* only if there is anything after '.' */ { word[nwords++] = "point"; while(*frac != '\0') /* just speak digits sequentiall */ { ch[0] = *frac++; temp = atoi(ch); word[nwords++] = dig09[temp]; } } } void parse_words(char *str) { p = str; while(1) { while( *p == ' ' && *p != '\0' ) p++; /* position p to head of word */ if( *p == '\0') break; /* EXIT endless loop */ sscanf(p, "%s", buf); /* get a word */ if(buf[0] == '#') { p++; /* char following # */ do_number(); } else { word[nwords] = (char *)malloc((size_t)(strlen(buf)+1)); strcpy(word[nwords++], buf); } while( *p != ' ' && *p != '\0') p++; } } void Serror(int r, int num) { fprintf(stderr,"saystring[%d]: %s\n", num, SNDSoundError(r)); } int AppendSoundFromFile(char *file, SNDSoundStruct *toSound) { int r, r2; SNDSoundStruct *sound2; char fullpath[MAXPATHLEN]; sprintf(fullpath, "%s/%s.snd", SOUNDDIR, file); r = SNDReadSoundfile(fullpath, &sound2); if(r) return(r); r = SNDInsertSamples(toSound, sound2, SNDSampleCount(toSound)); r2 = SNDFree(sound2); if(r) return(r); else return(r2); } int main(int argc, char *argv[]) { int r, i; int priority = 5; int preempt = 0; SNDSoundStruct *sound1; if(argc != 2) { printf("Usage example: saystring \"temperature #41.3 degrees is too_high\"\n"); printf(" another: saystring \"our fax number is #1 #2 #3 _ #4 #5 #6 #7\"\n"); printf(" will speak the strings. All words except for numbers must have\n"); printf(" a corresponding soundfile in directory %s.\n", SOUNDDIR); printf(" The string must be enclosed in quotation marks unless it is\n"); printf(" a single word. Numbers must be preceded by a # sign as above.\n"); exit(2); } /* Hmmm, it seems that we don't need SNDAcquire(), SNDRelease() calls for this */ /* Allocate an empty SNDSoundStruct */ r = SNDAlloc(&sound1, 0, SND_FORMAT_MULAW_8, SND_RATE_CODEC, 1, 4); if(r) { Serror(r, 2); goto do_exit; } /* Put the words in word[] array. nwords will have the total # of words */ parse_words(argv[1]); /* Concatenate all words into a single SNDSoundStruct */ for(i=0; i<nwords; i++) r = AppendSoundFromFile(word[i], sound1); /* ignore non-existent sound files */ r = SNDStartPlaying(sound1, TAG, priority, preempt, SND_NULL_FUN, SND_NULL_FUN); if(r) { Serror(r, 6); goto do_exit; } SNDWait(TAG); /* get blocked untill sound finishes */ do_exit: exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.