home *** CD-ROM | disk | FTP | other *** search
- /*
- * NAME
- * talk - speak text from the command line or a file
- *
- * SYNOPSIS
- * talk [-v] [-] [-f file] [string...]
- *
- * DESCRIPTION
- * this program uses speak.tos to speak text from the command line,
- * one or more files, or stdin. it is a front end to the old speak.tos
- * program.
- *
- * NOTES
- * talk uses two entry points into speak.tos. the process works
- * as follows: Load speak.tos into memory using the Mode 3 option
- * of the Pexec GEMDOS call (load/nogo). if successful, this call will
- * return the address of the base page of the loaded program.
- * Add 0x100 to this to get the first byte of the executable
- * code. then create "subroutines" by poking in rts instructions in
- * the right places. at this point, we can jump into speak.tos,
- * executing the 2 subroutines. you MUST save registers (not sure
- * which, i save 'em all) since speak clobbers them. the text to
- * speak is poked into a Cconrs-like buffer.
- *
- * here are the addresses (relative to start of program):
- *
- * routine 1 start 0x32 (muck with phonemes)
- * routine 1 rts 0x0e
- * routine 2 start 0x88 (generate speach)
- * routine 2 rts 0x6c
- *
- * input buffer 0x6eee
- *
- * calling the subroutines for phoneme and speech generation is
- * currently done in c_speak.s which also saves all the registers prior
- * to making the actual calls. i tried this in C and it failed. you
- * really need to save registers and i don't know a way to do that
- * without using assembler somehow (inline __asm__ or routine). note
- * that the inline assembler code in speak_line() has not been tested
- * and is for GNU C anyway.
- *
- * talk looks for speak.tos in the current directory, with environment
- * variable SPEAK or via the path.
- *
- * it would be nice to beef up the clean_line() function to remove
- * non-letters and perhaps fix things like numbers, acronyms, etc.
- *
- * ABOUT SPEAK.TOS
- * i know little of its history. it has a limited user interface, so
- * i know it got hacked up (like this here) for other uses. i picked
- * this up on compuserve ages ago. if you think you may have it but
- * the name has changed, here are some facts:
- *
- * sum speak.tos 56759 28
- * ls -l speak.tos 28416 bytes
- * strings -5 speak.tos turned up:
- *
- * Atari 520ST speech synthesizer V2.0
- *
- * MC68000/AY-3-8910 SPEECH SYNTHERSIZER V:2.0
- * Copyright 1986 A.D.BEVERIDGE & M.N.DAY
- * ALL RIGHTS RESERVED.
- *
- * so i guess it can't be used commercially.
- *
- * RELEASE NOTES
- * hacked together, originally in alcyon and now GNU C by:
- * Bill Rosenkranz, 1989? through 14 sep 1991
- * rosenkra@convex.com
- *
- * my last source mod dates from 18 sep 1990
- */
-
-
- #ifndef lint
- static char *rcsid_talk_c = "$Id: talk.c,v 2.1 1991/09/14 21:13:34 rosenkra Exp $";
- #endif /*lint*/
-
- /*
- * $Log: talk.c,v $
- * Revision 2.1 1991/09/14 21:13:34 rosenkra
- * clean up for release to atari.archive.
- *
- * Revision 2.0 1991/09/14 15:52:28 rosenkra
- * GNU C version. improved user interface (stdin, file(s), and cmdline;
- * search cwd, env, and PATH for speak, etc). also has inline assembly
- * for c_speak.s, but is still untested. includes which() function
- * which functions like which(1) only it can use any env variable (not
- * just PATH) and any of a pool of path name seperators.
- *
- * Revision 1.0 1991/09/14 01:51:22 rosenkra
- * Initial revision
- *
- */
-
-
- #include <stdio.h>
- #include <stdlib.h> /* for getenv() */
- #include <strings.h> /* for str*() */
- #include <osbind.h> /* for Pexec */
- #ifdef HAS_ACCESS
- #include <unistd.h> /* for access() */
- #endif /*HAS_ACCESS*/
-
- /*
- * name of the speak program
- */
- #define SPEAK_PROG "speak.tos"
-
- #ifdef DBG
- # undef DBG
- #endif
- #ifdef DEBUG
- # define DBG(x) printf x
- #else
- # define DBG(x)
- #endif
-
- #ifdef MAXLINE
- # undef MAXLINE
- #endif
- #define MAXLINE 256 /* max length of input line (stream or cmd) */
-
- #ifndef MAXPATH
- # define MAXPATH 256 /* max length of file path */
- #endif
-
- #ifdef SEARCH_PATH
- # define MAXENV 1024 /* max size of env string */
- #endif
-
- /*
- * globals:
- */
- char rts[2] = {0x4E, 0x75}; /* patch for subs (68000 rts inst) */
- long program; /* The base of SPEAK */
- char speak_path[MAXPATH]; /* for path of speak.tos */
- char line_buf[MAXLINE]; /* holds string to speak */
- int verbose = 0; /* tells what is going on */
-
-
- /*
- * local fcns:
- */
- void usage (void);
- void load_speak_prog (void);
- void speak_line (char *);
- void speak_stream (FILE *);
- void wait_ms (long);
- void c_speak (void);
- char *clean_line (char *);
- #ifdef SEARCH_PATH
- char *which (char *, char *, char *);
- #endif /*SEARCH_PATH*/
-
-
-
- /*------------------------------*/
- /* main */
- /*------------------------------*/
- int main (int argc, char *argv[])
- {
- FILE *in; /* stream if file */
-
-
-
- /*
- * check first arg for "-v"
- */
- argc--, argv++;
- if ((argv[0][0] == '-') && (argv[0][1] == 'v') && (argv[0][2] == 0))
- {
- verbose = 1;
- argc--, argv++;
- }
-
-
-
- /*
- * Load in SPEAK and fix it up...if successful, we'll be able
- * to TELL the user if he made any errors :-)
- */
- load_speak_prog();
-
-
-
- /*
- * parse command line
- */
- for ( ; argc && (**argv == '-'); argc--, argv++)
- {
- switch (*(*argv+1))
- {
- case 'v':
- if (strncmp (*argv, "-vers", 5) == 0)
- {
- printf ("%s\n", rcsid_talk_c);
- exit (0);
- }
- verbose = 1;
- break;
-
- case 'h':
- usage ();
- exit (0);
- break; /*NOTREACHED*/
-
- case 0:
- speak_stream (stdin);
- break;
-
- case 'f':
- /*
- * read file
- *
- * first open it...
- */
- argv++, argc--;
- if (!argc)
- {
- usage ();
- exit (1);
- }
- if ((in = fopen (*argv, "r")) == (FILE *) 0L)
- {
- printf ("talk: could not open data file\n");
- speak_line ("could not open data file");
- exit (1);
- }
-
- speak_stream (in);
-
- fclose (in);
- break;
-
- default:
- usage ();
- exit (1);
- break; /*NOTREACHED*/
- }
- }
-
-
- for ( ; argc && *argv; argc--, argv++)
- {
- /*
- * copy all words on command line to a buffer. use spaces
- * between words
- */
- line_buf[0] = '\0';
- while (argc--)
- {
- strcat (line_buf, *argv++);
- strcat (line_buf, " ");
- }
-
-
- /*
- * do it!
- */
- if (verbose)
- printf ("%s\n", line_buf);
-
- speak_line (line_buf);
- }
-
- exit (0);
- }
-
-
-
-
- /*------------------------------*/
- /* usage */
- /*------------------------------*/
- void usage ()
- {
- printf ("Usage: talk [-v] [-] [-f file] [words ...]\n");
- printf ("\n");
- printf ("-v means verbose and should be first argument (echo line).\n");
- printf ("- or -f file must appear before any words on command line.\n");
- printf ("can have more than one -f file option and optional words.\n");
- printf ("- means read from stdin.\n");
- printf ("\n");
- printf ("Example: talk -f f1 - -f f2 and now some words\n");
- printf ("\n");
- printf ("speaks file f1, then stdin, then file f2 then words on command.\n");
- }
-
-
-
-
- /*------------------------------*/
- /* load_speak_prog */
- /*------------------------------*/
- void load_speak_prog ()
- {
- long base; /* basepage location of loaded speak */
- char *penv; /* -> environment variable SPEAK */
- char *p;
- #ifndef HAS_ACCESS
- FILE *ftest; /* stream for speak.tos */
- #endif /*HAS_ACCESS*/
-
-
- speak_path[0] = 0;
-
-
- /*
- * find speak.tos. search order:
- *
- * 1) cwd
- * 2) env variable SPEAK contains full path (eg c:\bin\speak.tos)
- * 3) search path
- */
- #ifdef HAS_ACCESS
- if (access (SPEAK_PROG, F_OK) >= 0)
- {
- strcpy (speak_path, SPEAK_PROG);
-
- if (verbose)
- printf ("talk: found %s in current directory\n",
- speak_path);
- }
- #else /*! HAS_ACCESS*/
- if ((ftest = fopen (SPEAK_PROG, "r")) != (FILE *) 0L)
- {
- fclose (ftest);
- strcpy (speak_path, SPEAK_PROG);
-
- if (verbose)
- printf ("talk: found %s in current directory\n",
- speak_path);
- }
- #endif /*HAS_ACCESS*/
- else
- {
- if (verbose)
- printf ("talk: %s not in current directory. check env.\n",
- SPEAK_PROG);
-
- if ((penv = getenv ("SPEAK")) != (char *) NULL)
- {
- strcpy (speak_path, penv);
-
- if (verbose)
- printf ("found %s from SPEAK env variable.\n",
- speak_path);
- }
- #ifdef SEARCH_PATH
- else
- {
- if (verbose)
- printf ("talk: cannot find SPEAK in env. Search path.\n");
-
- if ((p = which (SPEAK_PROG, "PATH", ",")) == (char *) NULL)
- {
- printf ("talk: %s not found in PATH=%s\n",
- SPEAK_PROG,
- getenv ("PATH"));
- printf ("Either set environment variable SPEAK to the full path of %s\n", SPEAK_PROG);
- printf ("or make sure %s is in current directory or in your PATH.\n", SPEAK_PROG);
- exit(1);
- }
- else
- {
- strcpy (speak_path, p);
-
- if (verbose)
- printf ("talk: found %s from PATH\n",
- speak_path);
- }
- }
- #else /*! SEARCH_PATH*/
- else
- {
- printf ("talk: %s not found\n", SPEAK_PROG);
- printf ("Either set environment variable SPEAK to the full path of %s\n", SPEAK_PROG);
- printf ("or make sure %s is in current directory.\n", SPEAK_PROG);
- exit(1);
- }
- #endif /*SEARCH_PATH*/
- }
-
-
-
- /*
- * do load/nogo
- */
- base = (long) Pexec ((short) 3, (long) speak_path, (long) 0, (long) 0);
- if (base < 0)
- {
- printf ("talk: Pexec failure\n");
- exit (1);
- }
-
-
-
- /*
- * mark program start 256 bytes after basepage...
- */
- program = (long) (base + 0x00000100L);
-
-
-
- /*
- * fix the 2 subs by adding returns...
- */
- strncpy ((char *) (program+0x0e), rts, 2);
- strncpy ((char *) (program+0x6c), rts, 2);
-
- return;
- }
-
-
-
-
- /*------------------------------*/
- /* speak_stream */
- /*------------------------------*/
- void speak_stream (FILE *stream)
- {
- /*
- * read lines from stream calling speak_line on every one...
- */
- while (1)
- {
- /*
- * read a line. speak_line eliminates newline, etc.
- */
- fgets (line_buf, MAXLINE-1, stream);
- if (feof (stream))
- {
- break;
- }
-
-
- /*
- * do it! (printf allows ^C to terminate)
- */
- if (verbose)
- printf ("%s\n", line_buf);
-
- speak_line (line_buf);
- }
-
- return;
- }
-
-
-
- /*------------------------------*/
- /* speak_line */
- /*------------------------------*/
- void speak_line (char *ps)
- {
- register char *buffer;
- register char *pstart;
- long save_ssp;
-
-
-
- /*
- * clean up the line. clean_line ret NULL if line is empty (ie
- * devoid of readable text).
- *
- * this can get more sophisticated.
- */
- if ((pstart = clean_line (ps)) == (char *) NULL)
- return;
-
-
-
- /*
- * check for nothing to say...
- */
- if (strlen (pstart) == 0)
- return;
-
-
-
- /*
- * force the length of the the string not to exceed 125
- */
- pstart[125] = '\0';
-
-
-
- /*
- * note location of speak.tos input buffer
- */
- buffer = (char *) (program + 0x6EEEL);
-
-
-
- /*
- * this is a Cconrs-type buffer so our string has to be modified
- * by having the first byte the length of the buffer and the second
- * the length of the actual string. we copy directly to speak.tos
- * buffer here...
- */
- strcpy (buffer+2, pstart); /* data to speak */
- *(buffer+1) = strlen (pstart); /* and its length */
- *buffer = (char) 0xFE; /* size of entire buffer */
-
-
-
- /*
- * SPEAK will respeak the last line if the current
- * input line is a '\n'. The '\n' is replaced by a
- * space to defeat this redundant speech on double spaced
- * files.
- */
- if (!*(buffer+1))
- {
- buffer[1] = (char) 1;
- buffer[2] = ' ';
- buffer[3] = '\0';
- }
-
-
-
- /*
- * Call speak.
- */
- #if defined(__GNUC__) && defined(INLINE_ASM)
- __asm__ volatile \
- ("\
- movml d0-d7/a0-a6,sp@-; /* save all regs */ \
- moveq #50,d0; \
- addl %0,d0; \
- movel d0,a2; \
- jbsr a2@; \
- moveq #136,d0; \
- addl %0,d0; \
- movel d0,a2; \
- jbsr a2@; \
- movml sp@+, d0-d7/a0-a6" \
- : /* outputs */ \
- : "g"(program) /* inputs */ \
- : "d0", "a2" /* clobbered regs */ \
- );
- #else
- c_speak ();
- #endif /*__GNUC__&&INLINE_ASM*/
-
-
-
- /*
- * slight delay...then return. delay is needed to make a smooth
- * transition between continued lines. delay is in milliseconds.
- */
- #ifdef NEED_DELAY
- wait_ms (200L);
- #endif /*NEED_DELAY*/
-
- return;
- }
-
-
-
- /*------------------------------*/
- /* clean_line */
- /*------------------------------*/
- char *clean_line (char *ps)
- {
-
- /*
- * here we can get more sophisticated than this. we only kill newlines
- * and leading/trailing whitespace but could also delete punctuation,
- * expand numbers, abbreviations, etc.
- */
-
- register char *pstart;
- register char *pend;
-
-
-
- /*
- * kill any newlines just in case
- */
- pstart = ps;
- while (*pstart && ((*pstart == '\n') || (*pstart == '\r')))
- {
- *pstart = ' ';
- pstart++;
- }
-
-
-
- /*
- * kill leading whitespace
- */
- pstart = ps;
- while (*pstart && ((*pstart == ' ') || (*pstart == '\t')))
- pstart++;
-
-
-
- /*
- * kill trailing whitespace
- */
- pend = &pstart[strlen(pstart)-1];
- while (((long)pend > (long)pstart) && ((*pend==' ') || (*pend=='\t')))
- {
- *pend = '\0';
- pend--;
- }
-
-
- return (pstart);
- }
-
-
-
- #ifdef NEED_DELAY
-
- /*------------------------------*/
- /* wait_ms */
- /*------------------------------*/
-
- #define MSLOOP 125
-
- void wait_ms (long ms)
- {
-
- /*
- * wait prescribed number of miliseconds (approx).
- * inner loop takes about 1 ms on normal 8Mhz ST.
- */
-
- int i;
-
- if (ms <= 0)
- return;
-
- for ( ; ms > 0; ms--)
- for (i = MSLOOP; i > 0; i--)
- ;
-
- return;
- }
-
- #endif /*NEED_DELAY*/
-
-
- #ifdef SEARCH_PATH
-
- /*
- * NAME
- * which - search PATH directories for given file
- *
- * called by: anything
- *
- * calls: strpbrk, strtok, getenv, strcpy, access, strncpy, sprintf
- *
- * returns: ptr to full pathname of file or NULL if not found
- *
- * notes:
- *
- * file should be simple filename (i.e. nnnnnnnn.eee). if it contains
- * any / or \ characters and the file cannot be found in the given path,
- * a null ptr is returned. delim is list of possible path component
- * seperator (eg ", "). env_name should be "PATH" or "path" typically,
- * but can be anything that would be in the environment.
- *
- * ptr returned, if valid, points to static array maintained here. use
- * it or (potentially) loose it...
- *
- * typical call:
- *
- * file_full_path = (char *) which (filename, "PATH", ",");
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <strings.h>
- #ifdef HAS_ACCESS
- #include <unistd.h>
- #endif /*HAS_ACCESS*/
-
- #ifdef DBG
- # undef DBG
- #endif
- #ifdef DEBUG
- # define DBG(x) printf x
- #else
- # define DBG(x)
- #endif
-
- /*------------------------------*/
- /* which */
- /*------------------------------*/
- char *which (char *file, char *env_name, char *delim)
- {
- static char pathname[MAXPATH];
- char pbuf[MAXENV];
- char *p;
- #ifndef HAS_ACCESS
- FILE *fd;
- #endif /*HAS_ACCESS*/
-
-
-
- strcpy (pathname, file);
-
-
- /*
- * check the obvios: cwd
- */
- #ifdef HAS_ACCESS
- if (access (pathname, 0) != -1)
- return (pathname);
- #else /*! HAS_ACCESS*/
- if ((fd = fopen (pathname, "r")) != NULL)
- {
- fclose (fd);
- return (pathname);
- }
- #endif /*HAS_ACCESS*/
-
-
- /*
- * file not in cwd. if file contains a specific path (i.e. contains
- * a \ (or /) or if PATH environment is not set, return a NULL.
- * else search for file along PATH.
- */
- if (strpbrk (file, "\\/") || !(p = getenv (env_name)))
- {
- DBG (("which: env= %s\n", p));
- return ((char *) NULL);
- }
- DBG (("which: env= %s\n", p));
-
-
- /*
- * copy value of env_name
- */
- if (strlen (p) > MAXENV)
- strncpy (pbuf, p, MAXENV);
- else
- strcpy (pbuf, p);
-
-
- /*
- * start breaking up the string...
- */
- if (p = strtok (pbuf, delim))
- {
- do
- {
- #define lastchar(s) (p)[strlen(p)-1]
-
- DBG (("which: token= %s\n", p));
- if ((lastchar(p) == '\\') || (lastchar(p) == '/'))
- sprintf (pathname, "%0.50s%0.20s", p, file);
- else if (index (p, '\\'))
- sprintf (pathname, "%0.50s\\%0.20s", p, file);
- else if (index (p, '/'))
- sprintf (pathname, "%0.50s/%0.20s", p, file);
- else
- sprintf (pathname, "%0.50s\\%0.20s", p, file);
- DBG (("which: pathname= %s\n", pathname));
-
- #ifdef HAS_ACCESS
- if (access (pathname, 0) != -1)
- return (pathname);
- #else /*! HAS_ACCESS*/
- if ((fd = fopen (pathname, "r")) != (FILE *) NULL)
- {
- fclose (fd);
- return (pathname);
- }
- #endif /*HAS_ACCESS*/
- } while (p = strtok ((char *)0L, delim));
- }
-
-
- /*
- * if we get here, we did not find it...
- */
- return ((char *) NULL);
- }
-
- #endif /*SEARCH_PATH*/
-
-
-
-
-
-
-
-
- #if 0
-
- /*
- * c_speak.c - stub to invoke SPEAK.TOS
- *
- * this doe NOT work unless registers are saved before (*f)() is
- * invoked and restored after return. GNU C does not do this.
- */
-
- #ifndef lint
- static char *rcsid_c_speak_c = "$Id$";
- #endif
-
- /*
- * $Log$
- */
-
- /*
- * offsets from program start to where we jump...
- */
- #define CALL_1_OFFSET 0x32
- #define CALL_2_OFFSET 0x88
-
- /*
- * this is actually a pointer to the start of the loaded program
- */
- extern long program;
-
-
- /*------------------------------*/
- /* c_speak */
- /*------------------------------*/
- void c_speak ()
- {
- register void (*f)();
-
- /*
- * first call, set up phonemes, make call...
- */
- f = (void (*)()) (program + CALL_1_OFFSET);
- (*f)();
-
- /*
- * second call, speak...
- */
- f = (void (*)()) (program + CALL_2_OFFSET);
- (*f)();
-
- return;
- }
-
-
- #endif
-
-
-