home *** CD-ROM | disk | FTP | other *** search
- /* LPC.C -- MSDOS Front End for the DSP CARD 3 LPC Vocoder
- *
- * Copyright (C) by Alef Null 1992
- * Author(s): Jarkko Vuori, OH2LNS
- * Modification(s):
- * 26-Sep-92: corrected double CTRL-C bug
- * corrected file open bug while playing
- * added DSP CARD buffer control mechanism to remove audible clicks from playback
- * added DSP CARD presense detector
- * now uses the current flags in the vocoder
- * 29-Sep-92: added CD command
- * commands can now be given in short form (e.g. PL for PLAY)
- * 30-Sep-92: added monotonic mode
- * added file date output to the directory command
- * corrected initial DSP CARD presense status bug
- */
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <string.h>
- #include <signal.h>
- #include <conio.h>
- #include <time.h>
- #include <ctype.h>
- #include <dos.h>
- #include <direct.h>
- #include "serial.h"
-
- #define EXT "voi" // default filename extension
-
- #define ERROR fprintf(stderr, "Internal error (%d)\n", __LINE__)
- #define FILENAME(s) AddExtension((s), EXT)
- #define DIFFERENCE(w, r, d) ((((w) - (r) >= 0) ? (w) - (r) : 16 - ((r) - (w))) <= (d))
-
- #define PORT 1 // default serial port number
- #define BAUD 9600 // baud rate
-
- #define SYNC1 0x55 // frame sync words
- #define SYNC2 0xaa
- #define LPCBLKLEN 6 // number of one LPC block bytes (48 bit)
- #define BLKS 20 // number of 48-bit block in one frame
-
- typedef enum { True = -1, False = 0 } Bool;
- typedef struct {
- struct {
- unsigned char whisper:1; // flags bits
- unsigned char silence:1;
- unsigned char loopb:1;
- unsigned char monot:1;
- unsigned char curblkn:4; // then running frame counter
- } flags;
- char p_d;
- unsigned char data[BLKS*LPCBLKLEN];
- } VOCODERBLK;
- typedef struct {
- unsigned id;
- } FILEHEADER;
-
- FILE *playfd, *recordfd;
- VOCODERBLK in, out;
- FILEHEADER fileHeader = { 10964 };
- Bool fDSPSensed = True;
-
-
- /* ctrl-C handler (to make ctrl-C inactive) */
- void cdecl CtrlCHandler(void) {
- printf("Type 'QUIT' to quit the program\n");
- signal(SIGINT, CtrlCHandler);
- }
-
-
- static char *AddExtension(char *FileName, char *Extension) {
- static char Name[13];
- char *s;
-
- s = Name;
- while(*FileName && *FileName != '.')
- *s++ = *FileName++;
-
- if(*FileName)
- while(*s++ = *FileName++);
- else {
- *s++ = '.';
-
- while(*s++ = *Extension++);
- }
-
- return(Name);
- }
-
-
- /* check that the given fh contains a valid header */
- static Bool CheckHeader(FILE *fd) {
- FILEHEADER fh;
-
- if (fread(&fh, sizeof(FILEHEADER), 1, fd) != 1 || fh.id != fileHeader.id)
- return (False);
- else
- return (True);
- }
-
-
- /* write header */
- static void WriteHeader(FILE *fd) {
- fwrite(&fileHeader, sizeof(FILEHEADER), 1, fd);
- }
-
-
- /* write one block to the DSP Card */
- static void WriteVocoderBlock(void) {
- register unsigned char *p;
-
- WriteSerial(SYNC1); WriteSerial(SYNC2);
- for (p = (unsigned char *)&out; p < &out.data[BLKS*LPCBLKLEN]; p++)
- WriteSerial(*p);
- }
-
-
- /* Read one character from the console and at the same time handle serial line */
- static int getusrchr(void) {
- static enum { sync1, sync2, flg, pitch, datas } state = sync1;
- static Bool fFirstTime = True;
- static time_t tBlockRead;
- static unsigned char *byteptr;
- static char buffer[80];
- static char *head = buffer, *tail = buffer, *lineend = buffer;
- int c;
- #define NEXT(p) ((((p)+1) >= &buffer[80]) ? buffer : (p)+1)
- #define PREV(p) ((((p)-1) < buffer) ? &buffer[80-1] : (p)-1)
-
- if (!tBlockRead)
- time(&tBlockRead);
-
- /* check if user want something */
- while (True)
- if (!kbhit()) {
- /* no user activity, play with serial line */
- if ((c = ReadSerial()) != -1) {
- switch(state) {
- case sync1:
- if (c == SYNC1)
- state = sync2;
- break;
-
- case sync2:
- if (c == SYNC2)
- state = flg;
- else
- state = sync1;
- break;
-
- case flg:
- *(unsigned char *)&in.flags = (unsigned char)c;
- state = pitch;
- break;
-
- case pitch:
- in.p_d = (char)c;
- byteptr = in.data;
- state = datas;
- break;
-
- case datas:
- *byteptr++ = (unsigned char)c;
- if (byteptr > &in.data[BLKS*LPCBLKLEN-1]) {
- /* one block read */
- state = sync1;
-
- /* write it to the file if necessary */
- if (recordfd)
- fwrite(in.data, sizeof(in.data), 1, recordfd);
-
- /* record when this block was read */
- time(&tBlockRead);
-
- if (!fDSPSensed) {
- fprintf(stderr, "\bSYS INFO: DSP CARD 3 is back!\n>");
- fDSPSensed = True;
- }
-
- if (fFirstTime) {
- out.flags = in.flags;
- out.p_d = in.p_d;
- fFirstTime = False;
- }
- }
- break;
-
- default:
- ERROR;
- break;
- }
- } else
- /* output a new block if there is space left in the DSP input buffer */
- if (!fFirstTime) {
- if (DIFFERENCE(out.flags.curblkn, in.flags.curblkn, 3)) {
- /* read block from the file if necessary */
- if (playfd)
- if (fread(out.data, sizeof(out.data), 1, playfd) != 1) {
- /* play it again (sam) if needed */
- fseek(playfd, (long)sizeof(FILEHEADER), SEEK_SET);
- fread(out.data, sizeof(out.data), 1, playfd);
- }
-
- /* give one block to the Vocoder */
- WriteVocoderBlock();
-
- /* update running block number counter */
- out.flags.curblkn++;
- } else if (time(NULL) - tBlockRead > 2) {
- if (fDSPSensed) {
- fprintf(stderr, "\x007\bSYS INFO: DSP CARD 3 not connected\n>");
- fDSPSensed = False;
- }
-
- /* no DSP, try to write last block again */
- WriteVocoderBlock();
- time(&tBlockRead);
- }
- } else if (time(NULL) - tBlockRead > 2)
- if (fDSPSensed) {
- fprintf(stderr, "\x007\bSYS INFO: DSP CARD 3 not connected\n>");
- fDSPSensed = False;
- }
-
- /* return data if available */
- if (tail != lineend) {
- c = *tail;
- tail = NEXT(tail);
- return (c);
- }
- } else {
- /* keyboard has been pressed, read the given character */
- switch (c = getch()) {
- case '\x08':
- if (head != tail) {
- head = PREV(head);
- putch('\x08'); putch(' '); putch('\x08');
- }
- break;
-
- case '\r':
- if (NEXT(head) != tail) {
- putch('\r'); putch(*head = '\n');
- head = NEXT(head);
- lineend = head;
- } else
- putch('\x07');
- break;
-
- default:
- if (NEXT(head) != tail) {
- putch(*head = c);
- head = NEXT(head);
- } else
- putch('\x07');
- break;
- }
- }
-
- }
-
- /* Read input from the user, and partition the input to command and parameters */
- static Bool getline(char *cmd, char *arg) {
- int c;
-
- /* flush leading whitespace characters */
- while (isspace(c = getusrchr()) && c != '\n');
- if (c == '\n')
- return (False);
-
- /* then get first word on the line */
- do {
- *cmd++ = (char)toupper(c);
- } while (!isspace(c = getusrchr()));
- *cmd = *arg = '\0';
- if (c == '\n')
- return (True);
-
- /* flush leading whitespace characters */
- while (isspace(c) && c != '\n')
- c = getusrchr();
-
- /* and finally get the rest of the line */
- if (c != '\n') {
- do {
- *arg++ = (char)c;
- } while ((c = getusrchr()) != '\n');
- *arg = '\0';
- }
-
- return (True);
- }
-
-
- /* Return date string */
- static char *dateStr(unsigned date) {
- struct {
- int co_date; // date format
- char co_curr[5]; // currency symbol
- char co_thsep[2]; // thousands separator
- char co_desep[2]; // decimal separator
- char co_dtsep[2]; // date separator
- char co_tmsep[2]; // time separator
- char co_currstyle; // currency style
- char co_digits; // significant digits in currency
- char co_time; // time format
- long co_case; // case map
- char co_dasep[2]; // data separator
- char co_fill[10]; // filler
- } country_info;
- struct { // MSDOS directory date format
- unsigned day:5;
- unsigned month:4;
- unsigned year:7;
- } d;
- static char result[10+1];
-
- *(unsigned *)&d = date;
-
- /* first find the current output format */
- bdos(0x38, (unsigned)&country_info, 0x00);
-
- /* then formulate date using correct format */
- switch (country_info.co_date) {
- case 0: // USA
- sprintf(result, "%02d%s%02d%s%04d", d.month, country_info.co_dtsep, d.day, country_info.co_dtsep, d.year+1980);
- break;
-
- case 1: // Europe
- default:
- sprintf(result, "%02d%s%02d%s%04d", d.day, country_info.co_dtsep, d.month, country_info.co_dtsep, d.year+1980);
- break;
-
- case 2: // Japan
- sprintf(result, "%04d%s%02d%s%02d", d.year+1980, country_info.co_dtsep, d.month, country_info.co_dtsep, d.day);
- break;
- }
-
- return (result);
- }
-
- static void logo(void) {
- printf("LPC -- DSP CARD 3 2400 bit/s LPC Vocoder front end (%s)\n", __DATE__);
- printf("Copyright (C) by Alef Null 1992. All rights reserved.\n\n");
- }
-
- static void Help(char *line) {
- printf("Available commands (commands can be abbreviated):\n");
- printf("CD <directory> - change current directory\n");
- printf("DEL <filename> - delete given voice file\n");
- printf("DIR - show current voice files\n");
- printf("HELP - give this message\n");
- printf("MONOTONE [ON | OFF] - set/show whispering mode\n");
- printf("PITCH [value] - change/show pitch changing status\n");
- printf("PLAY <filename> - playback\n");
- printf("QUIT - quit the program\n");
- printf("RECORD <filename> - record\n");
- printf("STOP - stop playing/recording\n");
- printf("WHAT [EVERYTHING] - tell usefull information\n");
- printf("WHISPER [ON | OFF] - set/show whispering mode\n");
- }
-
- static void Why(char *line) {
- static char *answers[] = {
- "It feels good.",
- "How the hell should I know?",
- "Jacques make me do it.",
- "Time to get back to work.",
- "R.T.F.M.",
- "Stupid question.",
- "For people like you.",
- "What?",
- "Because it's there.",
- "Why not?",
- };
-
- printf("%s\n", answers[(int)(((double)rand()/32768.0)*10.0)]);
- }
-
-
- static void Record(char *line) {
- FILE *tmpFp;
-
- if (*line) {
- if (recordfd)
- printf("Allready recording\n");
- else if ((tmpFp = fopen(FILENAME(line), "wb")) == NULL)
- printf("Can't create recording file '%s'\n", FILENAME(line));
- else {
- WriteHeader(tmpFp);
- recordfd = tmpFp;
- }
- } else
- printf("Recording file must be specified\n");
- }
-
-
- static void Play(char *line) {
- FILE *tmpFp;
-
- if (*line) {
- if ((tmpFp = fopen(FILENAME(line), "rb")) == NULL)
- printf("Can't open playback file '%s'\n", FILENAME(line));
- else if (!CheckHeader(tmpFp)) {
- printf("'%s' is not a valid voice file\n", FILENAME(line));
- fclose(tmpFp);
- } else {
- if (playfd) fclose(playfd);
-
- playfd = tmpFp;
- out.flags.loopb = False;
- }
- } else
- printf("Playback file must be specified\n");
- }
-
-
- static void Stop(char *line) {
- if (recordfd) {
- fclose(recordfd);
- recordfd = NULL;
- }
- if (playfd) {
- fclose(playfd);
- playfd = NULL;
- out.flags.loopb = True;
- }
- }
-
-
- static void What(char *line) {
- if (!fDSPSensed)
- printf("No Alef Null DSP CARD Vocoder device detected\n\n");
- printf("Playback: %s\n", playfd ? "PLAYING" : "STOP");
- printf("Record: %s\n", recordfd ? "RECORDING" : "STOP");
-
- if (*line) {
- printf("\nVersion: %s\n", __DATE__);
- printf("Whisper mode: %s\n", out.flags.whisper ? "ON" : "OFF");
- printf("Monotone mode: %s\n", out.flags.monot ? "ON" : "OFF");
- printf("Pitch change: %d\n", (int)out.p_d);
- }
- }
-
- static void Whisper(char *line) {
- if (*line)
- out.flags.whisper = !stricmp(line, "ON");
- else
- printf("Whisper mode: %s\n", out.flags.whisper ? "ON" : "OFF");
- }
-
- static void Monotone(char *line) {
- if (*line)
- out.flags.monot = !stricmp(line, "ON");
- else
- printf("Monotone mode: %s\n", out.flags.monot ? "ON" : "OFF");
- }
-
- static void Pitch(char *line) {
- if (*line)
- out.p_d = (char)atoi(line);
- else
- printf("Pitch change: %d\n", (int)out.p_d);
- }
-
- static void Dir(char *line) {
- struct find_t voiFile;
-
- if (_dos_findfirst(FILENAME("*"), _A_NORMAL, &voiFile) == 0)
- do {
- *strchr(voiFile.name, '.') = '\0'; // erase extension
- printf("%-12s %4lus %s\n", voiFile.name, voiFile.size/(LPCBLKLEN*50), dateStr(voiFile.wr_date));
- } while (_dos_findnext(&voiFile) == 0);
- }
-
- static void Delete(char *line) {
- if (*line) {
- if (remove(FILENAME(line)) == -1)
- printf("Can't remove file '%s'\n", FILENAME(line));
- } else
- printf("Filename must be specified\n");
- }
-
- static void ChangeDir(char *line) {
- char *buf;
-
- if (*line) {
- if (chdir(line) == -1)
- printf("Can't change to directory '%s'\n", line);
- } else {
- buf = getcwd(NULL, 80);
- printf("Current directory '%s'\n", buf);
- free(buf);
- }
- }
-
- static void NotImplemented(char *line) {
- printf("Not yet implemented\n");
- }
-
- static void Exit(char *line) {
- Stop(NULL);
- CloseSerial();
- exit(0);
- }
-
- /*
- * Check if the command is reserved word
- *
- * returns pointer to specified function if match is found
- * NULL if no match is found
- */
- static void (*ChkReservedWord(const char *name))(char *line) {
- static struct rwtable {
- const char *rw_name;
- void (*rw_func)(char *line);
- } rwtable[] = {
- "?", Help, "CD", ChangeDir,
- "DEL", Delete, "DIR", Dir,
- "EXIT", Exit, "FUCK", NotImplemented,
- "HELP", Help, "MONOTONE", Monotone,
- "PITCH", Pitch, "PLAY", Play,
- "QUIT", Exit, "RECORD", Record,
- "STOP", Stop, "WHAT", What,
- "WHISPER", Whisper, "WHY", Why,
- };
- register struct rwtable *low = rwtable,
- *high = rwtable + sizeof(rwtable)/sizeof(struct rwtable) - 1,
- *mid;
- int c;
-
- /* binary search on reserved words table */
- while(low <= high) {
- mid = low + (high-low)/2;
- if(!(c = strncmp(mid->rw_name, name, strlen(name))))
- return(mid->rw_func);
- else if(c < 0)
- low = mid+1;
- else
- high = mid-1;
- }
-
- return(NULL);
- }
-
-
- int cdecl main(int argc, char *argv[]) {
- void (*fp)(char *line);
- int port = PORT, mode = 0;
- char cmd[80], arg[80];
- char option;
-
- /* first initialize random number generator */
- srand((unsigned)time(NULL));
-
- /* then parse arguments */
- argc--; argv++;
- while(argc > 0) {
- switch(**argv) {
- case '-':
- switch(option = *(++(*argv))) {
- /* port selection */
- case 'p':
- case 'P':
- port = atoi(++(*argv));
- break;
-
- default:
- fprintf(stderr, "unknown option '%c', type 'lpc ?' to get the allowed options\n", option);
- break;
- }
- break;
-
- case '?':
- default:
- fprintf(stderr, "usage: lpc [-p<portno>]\n");
- fprintf(stderr, "\t-p<portno> uses the specified (1 (default) or 2) serial port\n");
- return (0);
- break;
- }
-
- argc--; argv++;
- }
-
- /* then open serial line */
- signal(SIGINT, CtrlCHandler);
- if (!OpenSerial(port, BAUD)) {
- fprintf(stderr, "can't open file serial port COM%d\n", port);
- return (1);
- }
-
- /* and talk to the user */
- logo();
- while (True) {
- putchar('>');
-
- if (getline(cmd, arg)) {
- if (fp = ChkReservedWord(cmd))
- (*fp)(arg);
- else
- printf("Unknown command, try 'HELP'\n");
- }
- }
-
- CloseSerial();
- return (0);
- }
-