/* sound.c - Copyright 1985 STSC, Inc. Property of STSC, Inc. */ /* Quad SOUND external process for use with Quad-XPn. This is * a sample external process to provide a template for the creation of * other more useful external processes. A number of general purpose * routines are provided here: initresult() Sets up a result APL object (MENT) with the descriptor, rank, and number of elements set. varsize() Calculates the appropriate size of a result APL object from its descriptor, rank and number of elements. getarg() Reads an APL object from the standard input pipe into a local buffer. error() Routine to return an error condition to the main APL process. done() A terminate signal catcher for the clean up termination of the external process. * Two include files are used with the external process: varmac.h APL variable object descriptor include file. errmacro.h Defines for the possible errors returnable to the main APL process from the external process. * Note the use of the fprintf() routine, for returning printable * messages to the users terminal from the external process. The * fprintf() messages are not captured by APL but are very useful * for debugging purposes. LLG Nov 84 */ #include "varmac.h" #include "errmacro.h" #include #include #include #include #include #define STDIN 0 #define STDOUT 1 #define TRUE 1 #define FALSE 0 #define BUFSIZE 1024 /* Sample input buffer size */ #define BUFOUT 64 /* Sample output buffer size */ char leftarg[BUFOUT]; /* Left arg Input buffer */ char rightarg[BUFSIZE]; /* Right arg Input buffer */ char result[BUFOUT]; /* Output buffer */ int bfile; /* File descriptor of /dev/beeper */ int done() /* Exit routine */ { /** Clean up code belongs here **/ close(bfile); /* close(STDIN); close(STDOUT); */ exit(0); } main(argc, argv) /* Main entry point for test routine */ int argc; /* argument count and */ char *argv[]; /* ... vector passed down from main's caller */ { register int len, *row; signal(SIGTERM, done); bfile = open("/dev/beeper", O_RDWR + O_NDELAY); if (bfile < 0) { fprintf(stderr, "\n\rcannot open /dev/beeper\n\r"); exit(0); } while(1) { /* Loop until termination signal received. */ getarg(leftarg); /* Read and ignore Left argument */ len = getarg(rightarg); /* Data out of pipe, into buf */ if (len < 0) { /* Too much data for buffer */ error(WS_FULL); continue; } /* Argument must be either N-by-2 matrix or 2-elt vector */ switch ( *rank(rightarg) ) { case 2: if ( *(1+shape(rightarg))==2) break; error (LENGTH_ERROR); continue; case 1: if ( *shape(rightarg) ==2 ) break; default: error(RANK_ERROR); continue; } /* Descriptor must be INT; will not be coerced */ if (*desc(rightarg) != INT) { error(DOMAIN_ERROR); continue; } len = (int) *nelm(rightarg); row = (int *) values(rightarg); for (; len > 1; len -= 2) { /* A row at a time */ tone(row); row += 2; } /** Prepare result space **/ len = initresult(INT, 1, 0); if (len < 0) { error(WS_FULL); continue; } *shape(result) = 0; if (*length(result) != *tlength(result)) { error(SYSTEM_ERROR); continue; } /* Send result off to Parent */ /* fprintf(stderr, "writing %d bytes to pipe\r\n", len); */ write(STDOUT, result, len); } } int tone(row) /* Generate tone a la *PLUS PC */ int *row; { struct freqdur note; /* Frequency and duration of tone */ register int rc; note.frequency = (short) *row++; note.duration = (short) *row; /* WARNING: very low frequencies can cause a hardware reset */ if (note.frequency < 20 ) note.frequency = 65535; note.duration /= 10; /* PC compatible milliseconds */ if (note.duration < 5) { rc = ioctl(bfile, BEEP_NOW, ¬e); } else { do { /* Wait till previous note done, then BEEP */ rc = ioctl(bfile, BEEP, ¬e); } while (rc < 0); } return; } error(type) /* Return Error response to APL */ int type; { int errtyp[2]; errtyp[0] = -1; /* Flag Error response */ errtyp[1] = type; /* Error type */ write(STDOUT, errtyp, 8); /*** fprintf(stderr, "error in sound\r\n"); ****/ return; } int initresult(d, r, n) /* Define result buffer for return object */ register char d; /* descriptor byte */ register char r; /* rank byte */ register int n; /* nelm */ { register int len; /** Prepare result space **/ len = varsize(d, r, n); len += WSMGROH; /* Length and refcount too */ /* fprintf(stderr, "initresult> result %d, d %d, r %d, n %d\r\n", len, d, r, n);*/ if (len > BUFOUT) { /* fprintf(stderr, "initresult> error result length %d\r\n", len); */ return(-1); } *length(result) = len; /* Leading byte length of result */ *tlength(result) = len; /* Trailing byte length of result */ *refcount(result)= 1; /* Initialize reference count */ *desc(result) = d; /* Result Descriptor */ *rank(result) = r; /* Result rank */ *nelm(result) = n; /* Number of Elements */ /* fprintf(stderr, "initresult> result length %d\r\n", len); */ return(len); } int varsize(d, r, n) /* Computes size needed for a variable */ register char d; /* descriptor byte */ register char r; /* rank byte */ register int n; /* nelm */ { register int z = 4+4; /* desc,rank word + nelm word */ z += 4 * r; /* one fullword for each coordinate */ switch (d) { case CHAR: z += n; break; case BOOL: z += ( n >> 3 ) + ((n & 7 ) ? 1 : 0); break; case INT : z += n*4; break; case FLOAT: z += n*8; break; default: return(0); } /* Round up to fullword if needed */ z = 0xfffffffc & (z+3); return(z); } int getarg(buffer) /* Empty APL object from pipe into local buffer */ register char *buffer; /* Return length of data object, or -1 for error */ { register int len, bytes, n; register char *bufp; n = read(STDIN, buffer, 4); /* Read length of Input */ /* 4 bytes, a full word */ bytes = *(int *) buffer; /* Length of input data */ len = bytes - 4; /* Remainder to read */ if (bytes > BUFSIZE) { /* Too much, clean up, WS full */ while (len > 0) { n = read(STDIN, buffer, len); /* Purge rest of Input */ fprintf(stderr, "too much data, ask %d, got %d\r\n", len, n); len -= n; } return(-1); } bufp = buffer + 4; while (len > 0) { n = read(STDIN, bufp, len); /* Read rest of Input */ len -= n; bufp += n; } /* fprintf(stderr, "getarg> got %d bytes, nelm %d, desc %d, rank %d\r\n", bytes, *nelm(buffer), *desc(buffer), *rank(buffer)); */ return(bytes); }