#include "exec/types.h" /*Filename: pig.c */ #include "lattice/stdio.h" #include "lattice/ctype.h" /* Copyright March, 1986 by */ #include "libraries/translator.h" /* Thomas W. Clement. */ #include "devices/narrator.h" /* Licence is hereby given for */ #include "exec/exec.h" /* the non-commercial use and */ #include "exec/nodes.h" /* duplication of all or part of */ #include "exec/memory.h" /* this program, expressly */ #include "exec/interrupts.h" /* conditioned, however, upon the */ #include "exec/ports.h" /* inclusion of this copyright */ #include "exec/libraries.h" /* notice and licencing agreement */ #include "exec/io.h" /* in any copy made. */ #include "exec/execbase.h" #define REVISION 1 struct MsgPort *writeport = 0; /* Write reply port. */ struct narrator_rb *writeNarrator = 0; /* Pointer to IORB. */ struct Library *TranslatorBase = 0; /* Ptr to Translator fn. */ extern struct MsgPort *CreatePort(); /* External functions */ extern struct Library *OpenLibrary(); /* are declared here. */ char obuff[1024]; /* Buffer sent to translate device.*/ char phonemeBuff[2048]; /* Buffer for translated string. */ char *pobuff; /* Pointer to obuff. */ int error; /* Error code. */ UWORD Rate = 100; /* Rate of speaking voice. (Slower */ /* than usual default value.) */ UWORD Pitch = DEFPITCH; /* Pitch of speaking voice. (110) */ UWORD Sex = DEFSEX; /* Sex of speaking voice. (Male) */ UWORD Mode = DEFMODE; /* Mode of voice. (Natural) */ UWORD Sampfreq = 25000; /* Sampling freq. (A bit higher.) */ char audChanMasks[4] = { 3, 5, 10, 12 }; /* Audio chan. allocation */ /* map. see ch 12 ROM K.M. */ /* This program accepts characters from stdin until a ".", "!", or "?" is * seen, then prints the piglatin equivalent to standard output and * uses the AMIGA's speaking abilities to say the piglatin equivalent. */ main() { /* Main() assembles characters into words which are passed on to * pig() for conversion into pig latin. An imbedded apostrophe * is considered a part of the word. When a sentence is assembled, * it is passed on to sayit() for enunciation. */ char wbuff[64]; /* Single word buffer. */ char *pwbuff; /* Pointer to wbuff. */ int c; /* Current character. */ int nopig = 0; /* Flag for regular speech. */ void setup_speech(); /* Declare function. */ void cleanup(); /* Declare cleanup function. */ void set_voice(); /* Declare voice specifier. */ pobuff = obuff; /* Initialize pobuff. */ printf( "Do you want to set voice characteristics? ( y or n ): " ); gets( wbuff ); if( *wbuff == 'y' || *wbuff == 'Y' ) { set_voice(); /* Routine to change voice. */ } printf( "Piglatin or regular speech? ( 'p' or 'r' ) :" ); gets( wbuff ); if( *wbuff == 'r' || *wbuff == 'R' ) { nopig = -1; /* Set flag for normal speech.*/ } setup_speech(); /* Initialize speech stuff. */ printf( "Enter sentences ending with \".\", \"!\" or \"?\".\n" ); wbuff[0] = '\0'; /* Buffer starts at wbuff[1]. */ c = getchar(); /* Get first character. */ while( c != EOF ) /* Exit cleanly on EOF. */ { if( Chk_Abort() ) /* Exit cleanly on ^C or ^D. */ { printf( "** Break **\n" ); /* Announce break on ^C or ^D.*/ break; /* Gets to cleanup routines. */ } pwbuff = wbuff + 1; /* Pointer to 1st wbuff char. */ if( !isalpha(c) ) /* Skip all non-alphabetics. */ { *pobuff++ = c; /* Add the character to obuff.*/ if( c == '.' | c == '?' | c == '!' ) /* End of sentence? */ { *pobuff = '\0'; /* Null terminate obuff. */ if( !nopig ) { printf("%s\n", obuff); /* Print what's in the buffer.*/ } sayit(); /* Call speech routine. */ pobuff = obuff; /* Reset output buffer ptr. */ } c = getchar(); /* Update current character. */ } else /* Collect & pass word to pig.*/ { while( isalpha(c) || c == '\'' ) { *pwbuff++ = c; /* Word - alphabetic chars & */ c = getchar(); /* imbedded apostrophes. */ } *pwbuff = '\0'; /* Terminate word w/ null. */ if( nopig ) { strcpy( pobuff, wbuff + 1 ); /* Copy word to */ pobuff += pwbuff - ( wbuff + 1 ); /* obuff w/o change.*/ } else { pig( wbuff + 1 ); /* Sooeey. ( Call pig. ) */ } } } cleanup(); /* Close devices,ports, libs. */ exit( 0 ); } pig( word ) char *word; { /* Pig() takes a pointer to a word passed from main(), and assembles * the pig latin equivalent. */ char *sword = word; /* Pointer to word. */ int length; /* Length of string. */ if( *( sword + 1 ) == '\0' ) /* Don't change single letter */ { /* words. */ *pobuff++ = *sword; /* Add to output buff. */ if( *sword == 'a' || *sword == 'A' ) /* Add more if word was */ { /* "A" or "a"-- make it */ (void)strcpy( pobuff, "n-yay" ); /* "an-yay". (The next */ pobuff += 5; /* word will start with */ } /* a vowel.) */ } else if( isvowel( sword ) ) /* If it begins with a vowel */ { /* pigword is word with "yay" */ length = strlen( word ); /* added to the end. */ (void)strcpy( pobuff, word ); /* Copy word to obuff. */ pobuff += length; /* Advance pobuff. */ (void)strcpy( pobuff, "-yay" ); /* Copy "-yay" to obuff. */ pobuff += 4; /* Advance pobuff. */ } else /* Consonant starts a word. */ { while( !isvowel( sword ) && *sword != '\0' ) /* Find 1st vowel */ { /* or word end. */ ++sword; } if( *sword == '\0' ) /* If there are no vowels in */ { /* the word, don't change it. */ length = strlen( word ); (void)strcpy( pobuff, word ); /* Copy the word to obuff. */ pobuff += length; /* Advance pobuff. */ } else { if( isupper( *word ) ) /* If upper case, */ { *word += 32; /* change to lower case, and */ *sword = toupper( *sword ); /* change new 1st lett to UC. */ } length = strlen( sword ); /* Get length of substring. */ (void)strcpy( pobuff, sword ); /* Copy it to obuff. */ pobuff += length; /* Advance pobuff. */ *pobuff++ = '-'; /* Add a hyphen for clarity. */ *sword = '\0'; /* Terminate consonant part. */ length = strlen( word ); /* Get length of cons part. */ (void)strcpy( pobuff, word ); /* Copy cons part to obuff. */ pobuff += length; /* Advance pobuff. */ (void)strcpy( pobuff, "ay" ); /* Add "ay" to the string. */ pobuff += 2; /* Advance pobuff. */ } } } isvowel( p ) char *p; { /* This routine returns true if the character is a vowel. * For the purposes of this program, 'u' is not considered a * vowel if it follows a 'q'. 'Y' is considered a vowel if it * is followed by a consonant. Notice that 'y' will be treated * as a vowel in the program only where either: * 1. It starts a word and is followed by a consonant, or * 2. It is preceeded by a string of only consonants and is * followed by a consonant. */ char c; /* Current character, ( pointer to by p ). */ if( ( c = tolower( *p ) ) == 'a' || c == 'e' || c == 'i' || c == 'o' || ( c == 'u' && tolower( *( p-1 ) ) != 'q' ) || ( c == 'y' && !isvowel( p + 1 ) ) ) { return 1; /* Return true if a "vowel" as we define it. */ } return 0; /* Otherwise return false. */ } void setup_speech() { /* This function sets up the translator library and the speech device of * the AMIGA. If it fails for some reason, it trys to let you know why. */ if((TranslatorBase = OpenLibrary("translator.library", REVISION)) == NULL) { printf( "Can't open Translator library.\n" ); error = 1; cleanup(); } if( ( writeport = CreatePort( 0, 0 ) ) == NULL ) { printf( "CreatePort problems.\n" ); error = 2; cleanup(); } /* Note that memory is allocated directly, instead of using the * function CreateExtIO(). This is because I couldn't find this * function anywhere in my release. Anyway, this seems to work O.K. * so I suppose I can't complain. */ if( ( writeNarrator = (struct narrator_rb *)AllocMem( sizeof( struct narrator_rb), MEMF_PUBLIC | MEMF_CLEAR ) ) == NULL ) { printf( "Can't allocate memory for writeNarrator IORB.\n" ); error = 3; cleanup(); } /* Specify the type of node in the linked list, the priority of the * message, and the address of the prot created with CreatePort(). */ writeNarrator->message.io_Message.mn_Node.ln_Type = NT_MESSAGE; writeNarrator->message.io_Message.mn_Node.ln_Pri = 0; writeNarrator->message.io_Message.mn_ReplyPort = writeport; writeNarrator->ch_masks = audChanMasks; /* Audio channels. */ writeNarrator->nm_masks = sizeof( audChanMasks ); /* # of Audio chans. */ writeNarrator->message.io_Command = CMD_WRITE; /* Command for IO. */ if( OpenDevice( "narrator.device", 0, writeNarrator, 0 ) ) { printf( "Can't open narrator device.\n" ); error = 4; cleanup(); } writeNarrator->rate = Rate; /* Set these values to the */ writeNarrator->pitch = Pitch; /* defaults, or the user */ writeNarrator->sex = Sex; /* specified values if the */ writeNarrator->mode = Mode; /* function set_voice was */ writeNarrator->sampfreq = Sampfreq; /* called. */ return; } void cleanup() { if( writeNarrator ) /* If the narrator device had been */ { /* close it & free up memory. */ CloseDevice( writeNarrator ); FreeMem( writeNarrator, sizeof( struct narrator_rb ) ); } if( writeport ) { /* If the port had been */ DeletePort( writeport ); /* created, delete it. */ } if( TranslatorBase ) /* If the translator */ { /* library had been opened,*/ CloseLibrary( TranslatorBase ); /* close it. */ } if( error ) /* Tell user what went wrong. */ { fprintf( stderr, "Error #%d, execution terminated.\n", error ); exit( error ); } } sayit() { /* This function speaks the pig latin. It translates the string in * obuff, placing the result in phonemeBuff. It then sets a couple * of fields in the narrator IORB (Input Output Request Block), and * sends the phonemes into the ether. */ if( Translate( obuff, pobuff-obuff, phonemeBuff, 2048 ) ) { printf( "Translator output buffer overflow.\n" ); error = 5; cleanup(); } writeNarrator->message.io_Data = (APTR)phonemeBuff; /* Ph. source. */ writeNarrator->message.io_Length = strlen(phonemeBuff); /* Length. */ if( DoIO( writeNarrator ) ) { printf( "Can't perform DoIO.\n" ); error = 6; cleanup(); } } int atoi(s) char *s; /* This is a simple version of atoi suitable for our use. */ { /* ( atoi changes a string into an integer ). */ int n; for( n = 0; *s >= '0' && *s <= '9'; s++ ) { n = 10 * n + *s - '0'; } return( n ); } void set_voice() { char answer[10]; /* Char array for answers.*/ printf( "Male or female? ( m or f ): " ); gets( answer ); if( *answer == 'f' || *answer == 'F' ) { Sex = FEMALE; } printf( "How many words per minute? (40 to 400): " ); gets( answer ); if( *answer != '\0' ) { Rate = atoi( answer ); /* Convert answer to int. */ Rate = max( Rate, MINRATE ); /* Make Rate >= minimum. */ Rate = min( Rate, MAXRATE ); /* Make Rate <= maximum. */ } printf( "What pitch speech? (65 to 320): " ); gets( answer ); if( *answer != '\0' ) { Pitch = atoi( answer ); /* Convt answer to int. */ Pitch = max( Pitch, MINPITCH ); /* Make Pitch >= minimum. */ Pitch = min( Pitch, MAXPITCH ); /* Make Pitch <= maximum. */ } printf( "What sampling frequency? ( 5000 to 28000 ): " ); gets( answer ); if( *answer != '\0' ) { Sampfreq = atoi( answer ); /* Convt answer to int. */ Sampfreq = max( Sampfreq, MINFREQ ); /* Ensure that sampling */ Sampfreq = min( Sampfreq, MAXFREQ ); /* freq is w/in range. */ } printf( "What mode of speech? (Natural or Monotone): " ); gets( answer ); if ( *answer == 'M' || *answer == 'm' ) { Mode = ROBOTICF0; /* Monotone voice. */ } return; }