home *** CD-ROM | disk | FTP | other *** search
-
- /*
- SPEECH.C
- =======
-
- */
-
- #define __SPEECH__
-
- #include <unistd.h>
- #include "v9t9_common.h"
- #include "v9t9.h"
- #include "sound.h"
- #include "memory.h"
- #include "speech.h"
- #include "timer.h"
- #include "roms.h"
-
- #define _L LOG_SPEECH | LOG_INFO
- #include "tms5220r.c"
-
- char speechromfilename[64]="spchrom.bin";
-
- static struct tms5200 sp;
- static struct LPC lpc; /* LPC info */
-
- u8 speechrom[65536];
-
- static int speech_hertz = 8000;
- static int speech_length = 200;
- static s8 *speech_data;
-
-
- /****************************************************/
-
- static int speech_event_tag;
- static int in_speech_intr = 0; // mutex on speech_intr
-
- #define SPEECH_TIMEOUT (25+9)
-
- /****************************************************/
-
-
- static u8 swapped_nybbles[16] =
- {
- 0x0, 0x8, 0x4, 0xc,
- 0x2, 0xa, 0x6, 0xe,
- 0x1, 0x9, 0x5, 0xd,
- 0x3, 0xb, 0x7, 0xf
- };
-
- static u8
- swapbits(u8 in)
- {
- return (swapped_nybbles[in & 0xf] << 4) |
- (swapped_nybbles[(in & 0xf0) >> 4]);
- }
-
- /*
- static u8
- swapbits(u8 in)
- {
- in = ((in >> 1) & 0x55) | ((in << 1) & 0xaa);
- in = ((in >> 2) & 0x33) | ((in << 2) & 0xcc);
- in = ((in >> 4) & 0x0f) | ((in << 4) & 0xf0);
- return in;
- }
- */
-
- /******************************************************/
-
- static void
- tms5200purgeFIFO(void)
- {
- sp.bit = sp.bits = sp.out = sp.in = sp.len = 0;
- }
-
- static void
- LPCinit(void)
- {
- memset((void *) &lpc, 0, sizeof(lpc));
- lpc.decode |= FL_first;
- /* Reset excitation filters */
- lpc.ns1 = 0xaaaaaaaa;
- lpc.ns2 = 0x1;
- }
-
- static void
- SpeechOn(void)
- {
- if (!speech_event_tag)
- speech_event_tag = TM_UniqueTag();
-
- TM_SetEvent(speech_event_tag, TM_HZ * 100 / 40, 0,
- TM_REPEAT | TM_FUNC, speech_intr);
- }
-
- static void
- SpeechOff(void)
- {
- TM_ResetEvent(speech_event_tag);
- }
-
- static void
- tms5200reset(void)
- {
- logger(_L | L_1, "Speech reset");
- sp.status = SS_BE | SS_BL;
- tms5200purgeFIFO();
- sp.command = 0x70;
- sp.data = 0;
- sp.addr = 0; sp.addr_pos = 0;
- sp.gate = GT_RSTAT | GT_WCMD;
- SpeechOff();
- sp.status &= ~SS_SPEAKING;
- sp.timeout = SPEECH_TIMEOUT;
- LPCinit();
- in_speech_intr = 0;
- }
-
- static u8
- tms5200read(void)
- {
- sp.addr_pos = 0;
- if (sp.addr >= 32768)
- sp.data = 0;
- else
- sp.data = speechrom[sp.addr];
- sp.addr++;
- sp.gate = (sp.gate & ~GT_RSTAT) | GT_RDAT;
- logger(_L | L_2, "Speech read: %02X\n\n", sp.data);
- return sp.data;
- }
-
- static u8
- tms5200peek(void)
- {
- sp.addr_pos = 0;
- if (sp.addr >= 32768)
- sp.data = 0;
- else
- sp.data = speechrom[sp.addr];
- sp.gate = (sp.gate & ~GT_RSTAT) | GT_RDAT;
- return sp.data;
- }
-
- static void
- tms5200loadAddress(u32 nybble)
- {
- sp.addr_pos = (sp.addr_pos + 1) % 5;
- sp.addr = (sp.addr >> 4) | (nybble << 16);
- logger(_L | L_2, "Speech addr = %04X\n", sp.addr);
- }
-
- static void
- tms5200readAndBranch(void)
- {
- u32 addr;
-
- sp.addr_pos = 0;
- addr = (tms5200read() << 8) + tms5200read();
- sp.addr = (sp.addr & 0xc000) | (addr & 0x3fff);
- sp.gate = (sp.gate & ~GT_RDAT) | GT_RSTAT;
- }
-
- static void
- tms5200speak(void)
- {
- logger(_L | L_1, "Speaking phrase at %04X\n", sp.addr);
- sp.status |= SS_TS;
- sp.gate = (sp.gate & ~GT_WDAT) | GT_WCMD; /* just in case */
- sp.bit = 0; /* start on byte boundary */
- // flush existing sample
- SPEECHPLAY(vms_Speech, NULL, 0L, speech_hertz);
- sp.status |= SS_SPEAKING;
- while (sp.status & SS_SPEAKING)
- speech_intr(); // not scheduled
- LPCinit();
- }
-
- static void
- tms5200speakExternal(void)
- {
- logger(_L | L_1, "Speaking external data");
- sp.gate = (sp.gate & ~GT_WCMD) | GT_WDAT; /* accept data from I/O */
- tms5200purgeFIFO();
- SpeechOn(); /* call speech_intr every 25 ms */
- sp.status |= SS_SPEAKING;
- sp.timeout = SPEECH_TIMEOUT;
- }
-
- /* Undocumented and unknown function... */
- static void
- tms5200loadFrameRate(u8 val)
- {
- if (val & 0x4) {
- /* variable */
- } else {
- /* frameRate = val & 0x3; */
- }
- }
-
- static void
- tms5200command(u8 cmd)
- {
- sp.command = cmd & 0x70;
- logger(_L | L_3, "Cmd=%02X Status: %02X\n\n", cmd, sp.status);
- switch (sp.command) {
- case 0x00:
- case 0x20:
- tms5200loadFrameRate(cmd & 0x7);
- break;
- case 0x10:
- tms5200read();
- break;
- case 0x30:
- tms5200readAndBranch();
- break;
- case 0x40:
- tms5200loadAddress(cmd & 0xf);
- break;
- case 0x50:
- tms5200speak();
- break;
- case 0x60:
- tms5200speakExternal();
- break;
- case 0x70:
- tms5200reset();
- break;
- /* default: ignore */
- }
- }
-
- static void
- tms5200writeFIFO(u8 val)
- {
- sp.fifo[sp.in] = swapbits(val);
- sp.in = (sp.in + 1) & 15;
- logger(_L | L_3, "FIFO write: %02X len=%d\n", val, sp.len);
- if (sp.len < 16)
- sp.len++;
- sp.timeout = SPEECH_TIMEOUT;
- sp.status &= ~SS_BE;
- if (sp.len > 8) {
- sp.status &= ~SS_BL;
- speech_intr();
- }
- }
-
- static u8
- tms5200readFIFO(void)
- {
- u8 ret = sp.fifo[sp.out];
-
- logger(_L | L_3, "FIFO read: %02X len=%d\n", ret, sp.len);
-
- if (sp.len == 0) {
- sp.status |= SS_BE;
- tms5200reset();
- SpeechOff();
- logger(_L | L_1, "Speech timed out\n");
- }
-
- if (sp.len > 0) {
- sp.out = (sp.out + 1) & 15;
- sp.len--;
- }
- if (sp.len < 8)
- sp.status |= SS_BL;
- if (sp.len == 0) {
- sp.status |= SS_BE;
- }
- return ret;
- }
-
- static u8
- tms5200peekFIFO(void)
- {
- return sp.fifo[sp.out];
- }
-
-
- /*
- Fetch so many bits.
-
- This differs if we're reading from vocabulary or FIFO, in terms
- of where a byte comes from, but that's all.
-
- When reading from the FIFO, we only execute ...readFIFO when we
- are finished with the byte.
- */
- static u32
- LPCfetch(int bits)
- {
- u32 cur;
-
- if (sp.gate & GT_WDAT) { /* from FIFO */
- if (sp.bit + bits >= 8) { /* we will cross into the next byte */
- cur = tms5200readFIFO() << 8;
- cur |= tms5200peekFIFO(); /* we can't read more than 6 bits,
- so no poss of crossing TWO bytes */
- } else
- cur = tms5200peekFIFO() << 8;
- } else { /* from vocab */
-
- if (sp.bit + bits >= 8) {
- cur = tms5200read() << 8;
- cur |= tms5200peek();
- } else
- cur = tms5200peek() << 8;
- }
-
- /* Get the bits we want. */
- cur = (cur << (sp.bit + 16)) >> (32 - bits);
-
- /* Adjust bit ptr */
- sp.bit = (sp.bit + bits) & 7;
-
- sp.bits += bits;
- return cur;
- }
-
-
- /***************************************************************
- This section handles decoding one LPC equation into the 'lpc'
- structure.
- ****************************************************************/
-
- #define SHIFT 4
- #define KTRANS(x) (x)
-
- static void
- LPCclearToSilence(void)
- {
- lpc.pnv = 12;
- lpc.env = 0;
- memset(lpc.knv, 0, sizeof(lpc.knv));
-
- lpc.knv[0] = KTRANS(k1table[0]);
- lpc.knv[1] = KTRANS(k2table[0]);
- lpc.knv[2] = KTRANS(k3table[0]);
- lpc.knv[3] = KTRANS(k4table[0]);
- lpc.knv[4] = KTRANS(k5table[0]);
- lpc.knv[5] = KTRANS(k6table[0]);
- lpc.knv[6] = KTRANS(k7table[0]);
- lpc.knv[7] = KTRANS(k8table[0]);
- lpc.knv[8] = KTRANS(k9table[0]);
- lpc.knv[9] = KTRANS(k10table[0]);
-
- // if the previous frame was unvoiced,
- // it would sound bad to interpolate.
- // just clear it all out.
- if (lpc.decode & FL_unvoiced) {
- lpc.pbf = 12;
- lpc.ebf = 0;
- memset(lpc.kbf, 0, sizeof(lpc.kbf));
-
- lpc.kbf[0] = KTRANS(k1table[0]);
- lpc.kbf[1] = KTRANS(k2table[0]);
- lpc.kbf[2] = KTRANS(k3table[0]);
- lpc.kbf[3] = KTRANS(k4table[0]);
- lpc.kbf[4] = KTRANS(k5table[0]);
- lpc.kbf[5] = KTRANS(k6table[0]);
- lpc.kbf[6] = KTRANS(k7table[0]);
- lpc.kbf[7] = KTRANS(k8table[0]);
- lpc.kbf[8] = KTRANS(k9table[0]);
- lpc.kbf[9] = KTRANS(k10table[0]);
- }
- }
-
-
- static void
- LPCreadEquation(void)
- {
- char txt[256], *tptr = txt;
-
- sp.bits = 0;
-
- /* Copy now-old 'new' values into 'buffer' values */
- lpc.ebf = lpc.env;
- lpc.pbf = lpc.pnv;
- memcpy(lpc.kbf, lpc.knv, sizeof(lpc.kbf));
-
- /* Read energy */
- lpc.env = LPCfetch(4);
- tptr += sprintf(tptr, "E: %d ", lpc.env);
- if (lpc.env == 15) {
- lpc.decode |= FL_last;
- sp.status &= ~SS_TS; /* we will go one more frame to
- interpolate to silence, then speech_event
- will be reset */
- } else if (lpc.env == 0) { /* silent frame */
- LPCclearToSilence(); /* clear params */
- lpc.decode |= FL_nointerp;
- } else {
- /* Repeat bit */
- lpc.rpt = LPCfetch(1);
- tptr += sprintf(tptr, "R: %d ", lpc.rpt);
-
- /* Pitch code */
- lpc.pnv = LPCfetch(6);
- tptr += sprintf(tptr, "P: %d ", lpc.pnv);
-
- if (lpc.pnv == 0) { /* unvoiced */
- if (lpc.decode & FL_unvoiced) /* voiced before? */
- lpc.decode |= FL_nointerp; /* don't interpolate */
- else
- lpc.decode &= ~FL_nointerp;
- lpc.decode |= FL_unvoiced;
- lpc.pnv = 12; /* set some pitch */
-
- if (lpc.ebf == 0) /* previous frame silent? */
- lpc.decode |= FL_nointerp;
- } else { /* voiced */
-
- lpc.pnv = pitchtable[lpc.pnv] >> 8;
-
- if (lpc.decode & FL_unvoiced) /* unvoiced before? */
- lpc.decode |= FL_nointerp; /* don't interpolate */
- else
- lpc.decode &= ~FL_nointerp;
-
- lpc.decode &= ~FL_unvoiced;
- }
-
- /* translate energy */
- lpc.env = energytable[lpc.env];
-
- /* Get K parameters */
-
- if (!lpc.rpt) { /* don't repeat previous frame? */
- u32 tmp;
-
- tmp = LPCfetch(5);
- lpc.knv[0] = KTRANS(k1table[tmp]);
- tptr += sprintf(tptr, "K0: %d ", tmp);
-
- tmp = LPCfetch(5);
- lpc.knv[1] = KTRANS(k2table[tmp]);
- tptr += sprintf(tptr, "K1: %d ", tmp);
-
- tmp = LPCfetch(4);
- lpc.knv[2] = KTRANS(k3table[tmp]);
- tptr += sprintf(tptr, "K2: %d ", tmp);
-
- tmp = LPCfetch(4);
- lpc.knv[3] = KTRANS(k4table[tmp]);
- tptr += sprintf(tptr, "K3: %d ", tmp);
-
- if (!(lpc.decode & FL_unvoiced)) { /* unvoiced? */
- tmp = LPCfetch(4);
- lpc.knv[4] = KTRANS(k5table[tmp]);
- tptr += sprintf(tptr, "K4: %d ", tmp);
-
- tmp = LPCfetch(4);
- lpc.knv[5] = KTRANS(k6table[tmp]);
- tptr += sprintf(tptr, "K5: %d ", tmp);
-
- tmp = LPCfetch(4);
- lpc.knv[6] = KTRANS(k7table[tmp]);
- tptr += sprintf(tptr, "K6: %d ", tmp);
-
- tmp = LPCfetch(3);
- lpc.knv[7] = KTRANS(k8table[tmp]);
- tptr += sprintf(tptr, "K7: %d ", tmp);
-
- tmp = LPCfetch(3);
- lpc.knv[8] = KTRANS(k9table[tmp]);
-
- tptr += sprintf(tptr, "K8: %d ", tmp);
-
- tmp = LPCfetch(3);
- lpc.knv[9] = KTRANS(k10table[tmp]);
- tptr += sprintf(tptr, "K9: %d ", tmp);
- } else {
- lpc.knv[4] = KTRANS(k5table[0]);
- lpc.knv[5] = KTRANS(k6table[0]);
- lpc.knv[6] = KTRANS(k7table[0]);
- lpc.knv[7] = KTRANS(k8table[0]);
- lpc.knv[8] = KTRANS(k9table[0]);
- lpc.knv[9] = KTRANS(k10table[0]);
- }
- }
- }
- logger(_L | L_1, "Equation: %s\n", txt);
-
- logger(_L | L_1, "ebf=%d, pbf=%d, env=%d, pnv=%d\n",
- lpc.ebf, lpc.pbf, lpc.env, lpc.pnv);
- }
-
- /*******************************************************************
- This section handles the 'execution' of an LPC equation.
- ********************************************************************/
-
- /*
- Interpolate "new" values and "buffer" values.
- */
- static void
- LPCinterpolate(int period)
- {
- int x;
-
- if (!(lpc.decode & FL_nointerp)) {
- lpc.ebf += (lpc.env - lpc.ebf) / interp_coeff[period];
- lpc.pbf += (lpc.pnv - lpc.pbf) / interp_coeff[period];
- for (x = 0; x < 11; x++)
- lpc.kbf[x] += (lpc.knv[x] - lpc.kbf[x]) / interp_coeff[period];
- }
- /* logger(_L|LOG_USER, "[%d]\n", lpc.kbf[0]);
- if (period == 7) logger(_L|LOG_USER,"\n");*/
-
- logger(_L|L_1, "[%d] ebf=%d, pbf=%d\n", period, lpc.ebf, lpc.pbf);
- }
-
- #define ONE 32768
-
- // this is safe since our values are ~14 bits
- #define MD(a,b) (((a)*(b))/ONE)
- #define B(i) lpc.b[i]
- #define Y(i) lpc.y[i]
- #define K(i) lpc.kbf[i]
- #define U Y(10)
-
- static void
- LPCcalc(void)
- {
- int frames, bytes, stage;
- s8 *ptr;
-
- ptr = speech_data;
- if (!ptr)
- return;
-
- frames = 8;
- while (frames--) {
- bytes = speech_length / 8;
-
- while (bytes--) {
- s32 samp;
-
- /* Get excitation data in U */
- if ((lpc.decode & FL_unvoiced)) {
- U = (lpc.ns1 & 1) ? lpc.ebf / 4 : -lpc.ebf / 4;
-
- /* noise generator */
- lpc.ns1 = (lpc.ns1 << 1) | (lpc.ns1 >> 31);
- lpc.ns1 ^= lpc.ns2;
- if ((lpc.ns2 += lpc.ns1) == 0)
- lpc.ns2++;
- } else {
- U =
- lpc.ppctr < 41
- ? chirptable[lpc.ppctr] * lpc.ebf / 256
- : 0;
- if (lpc.pbf)
- lpc.ppctr = (lpc.ppctr + 1) % lpc.pbf;
- else
- lpc.ppctr = 0;
- }
-
- /* -----------------------------------------
- 10-stage lattice filter.
-
- range 1..10 here, 0..9 in our arrays
-
- Y10(i) = U(i) - K10*B10(i-1) U(i)=excitation
- ----
- Y9(i) = Y10(i) - K9*B9(i-1)
- B10(i)= B9(i-1) + K9*Y9(i)
- ----
- ...
- Y1(i) = Y2(i) - K1*B1(i-1)
- B2(i) = B1(i-1) + K1*Y1(i)
- ----
- B1(i) = Y1(i)
- ----------------------------------------- */
-
- /* Stage 10 is different than the others.
- Instead of calculating B11, we scale the excitation by
- the energy.
-
- */
-
- for (stage = 9; stage >= 0; stage--) {
- Y(stage) = Y(stage + 1) - MD(K(stage), B(stage));
- B(stage + 1) = B(stage) + MD(K(stage), Y(stage));
- }
-
- samp = Y(0);
- B(0) = samp;
-
- *ptr++ = (samp > 511 ? 127 : samp < -512 ? -128 : samp >> 2);
- }
-
- /* Interpolate values from *nv to *bf */
- LPCinterpolate(7 - frames);
- }
- }
-
-
- /*
- Interpolation here is from the previous LPC equation.
- Another 8 rounds of parameter interpolation occur inside
- the calculation.
- */
- static void
- LPCexec(void)
- {
- if (lpc.decode & (FL_nointerp | FL_first))
- lpc.decode &= ~FL_first;
-
- lpc.ppctr = 0;
-
- memset(lpc.y, 0, sizeof(lpc.y));
- memset(lpc.b, 0, sizeof(lpc.b));
-
- LPCcalc();
-
- /* spit it out */
- if (speech_data)
- SPEECHPLAY(vms_Speech, speech_data, speech_length, speech_hertz);
-
- if (lpc.decode & FL_last) { /* last frame */
- logger(_L | L_1, "Done with speech phrase\n");
- SpeechOff(); /* stop interrupting */
- sp.status &= ~SS_SPEAKING; /* stop interrupting */
- sp.gate = (sp.gate & ~GT_WDAT) | GT_WCMD;
- }
- }
-
- /*
- One LPC frame consists of decoding one equation (or repeating,
- or stopping), and calculating a speech waveform and outputting it.
-
- This happens during an interrupt.
-
- If we're here, we have enough data to form any one equation.
- */
- static void
- LPCframe(void)
- {
- LPCreadEquation();
- if (sp.status & SS_SPEAKING) /* didn't get empty condition */
- LPCexec();
- }
-
-
-
- void
- speech_intr(void)
- {
- if (in_speech_intr)
- return;
- in_speech_intr = 1;
-
- logger(_L | L_2, "In speech Interrupt\n");
- if (sp.gate & GT_WDAT) { /* direct data */
- if (!(sp.status & SS_TS)) /* not talking yet... we're waiting for */
- if (sp.status & SS_BL) /* enough data in the buffer */
- goto out; /* ... not yet */
- else
- sp.status |= SS_TS; /* whee! Start talking */
- else if (sp.status & SS_BL) {
- if (sp.timeout-- <= 0)
- tms5200reset();
- goto out;
- }
- }
- LPCframe(); /* execute a frame */
- out:
- logger(_L | L_2, "Out of speech interrupt\n");
- in_speech_intr = 0;
- }
-
-
- /********************/
-
- u16
- speech_mmio_get_addr(void)
- {
- return sp.addr;
- }
-
- void
- speech_mmio_set_addr(u16 addr)
- {
- sp.addr = addr;
- }
-
- bool
- speech_mmio_addr_is_complete(void)
- {
- return sp.addr_pos == 0 || sp.addr_pos == 5;
- }
-
- void
- speech_mmio_write(u8 val)
- {
- if (sp.gate & GT_WCMD)
- tms5200command(val);
- else
- tms5200writeFIFO(val);
- }
-
- s8 speech_mmio_read(void)
- {
- if (sp.gate & GT_RSTAT) {
- logger(_L | L_2, "Status: %02X\n\n", sp.status);
- return sp.status & (SS_TS | SS_BE | SS_BL);
- } else {
- sp.gate = (sp.gate & ~GT_RDAT) | GT_RSTAT;
- return sp.data;
- }
- }
-
- mrstruct speech_handler =
- {
- speechrom, speechrom, 0L, // cannot write
- NULL, NULL,
- NULL, NULL
- };
-
- void
- speech_memory_init(void)
- {
- memory_insert_new_entry(MEMENT_SPEECH, 0x0000, 0x10000,
- "Speech ROM",
- // 0L /*filename*/, 0L /*fileoffs*/,
- speechromfilename, 0 /*fileoffs*/,
- &speech_handler);
-
- }
-
- /************************/
-
- static void
- speech_initLPC(void)
- {
- if (!(features & FE_SPEECH)) {
- features &= ~(FE_PLAYSPEECH | FE_SPEECH);
- logger(_L | LOG_USER, "Sound module cannot play speech, speech disabled.\n\n");
- } else
- logger(_L | L_0, "Setting up LPC speech...\n\n");
- }
-
-
- /***********************************************/
-
- static
- DECL_SYMBOL_ACTION(speech_set_sample_length)
- {
- if (task == csa_WRITE) {
- xfree(speech_data);
- if (speech_length <= 0) speech_length = 1;
- speech_data = (s8*) xmalloc(speech_length);
- }
- return 1;
- }
-
- static
- DECL_SYMBOL_ACTION(speech_define_speech_rom)
- {
- char cmdbuf[1024];
- char *fname;
-
- if (task == csa_READ) {
- command_arg_get_string(SYM_ARG_1st, &fname);
- if (!fname || !*fname)
- return 0;
- else
- return (iter == 0);
- }
-
- command_arg_get_string(SYM_ARG_1st, &fname);
- if (!*fname)
- fname = "spchrom.bin";
- sprintf(cmdbuf, "DefineMemory \"RS\" 0x0000 -0x10000 \"%s\" 0x0 \"Speech ROM\"\n", fname);
- return command_parse_text(cmdbuf);
- }
-
- int
- speech_preconfiginit(void)
- {
- command_symbol_table *speechcommands =
- command_symbol_table_new("Speech Options",
- "These are commands for controlling speech synthesis",
-
- command_symbol_new("PlaySpeech",
- "Control whether speech is played",
- c_STATIC,
- NULL /*action*/,
- RET_FIRST_ARG,
- command_arg_new_toggle
- ("on|off",
- "toggle speech on or off",
- NULL /* action */ ,
- ARG_NUM(features),
- FE_PLAYSPEECH,
- NULL /* next */ )
- ,
-
- command_symbol_new("SpeechROMFileName",
- "Name of speech ROM",
- c_DYNAMIC,
- speech_define_speech_rom /* action */ ,
- RET_FIRST_ARG,
- command_arg_new_string
- ("file",
- "name of binary image",
- NULL /* action */,
- NEW_ARG_NEW_STRBUF,
- NULL /* next */ )
- ,
-
- command_symbol_new("SpeechHertz",
- "Set sample rate for speech",
- c_STATIC,
- NULL /*action*/,
- RET_FIRST_ARG,
- command_arg_new_num
- ("hertz",
- "normal value is 8000",
- NULL /* action */ ,
- ARG_NUM(speech_hertz),
- NULL /* next */ )
- ,
-
- command_symbol_new("SpeechSampleLength",
- "Set sample length for a unit of speech",
- c_STATIC,
- speech_set_sample_length,
- RET_FIRST_ARG,
- command_arg_new_num
- ("length",
- "in bytes, normal value is 200",
- NULL /* action */ ,
- ARG_NUM(speech_length),
- NULL /* next */ )
- ,
-
- NULL /*next*/)))),
- NULL /*sub*/,
- NULL /*next*/
- );
-
- command_symbol_table_add_subtable(universe, speechcommands);
- speech_length = 200;
- speech_data = (s8*) xmalloc(speech_length);
- LPCinit();
- features |= FE_SPEECH|FE_PLAYSPEECH;
- return 1;
- }
-
- int
- speech_postconfiginit(void)
- {
- /* if (!loadspeech(romspath, systemromspath,
- speechromfilename, speechrom)) {
- features &= ~FE_PLAYSPEECH;
- }
- */
- speech_memory_init();
- speech_initLPC();
- tms5200reset();
- return 1;
- }
-
- int
- speech_restart(void)
- {
- return 1;
- }
-
- void
- speech_restop(void)
- {
- }
-
- void
- speech_shutdown(void)
- {
- xfree(speech_data);
- }
-
- /*
- * The least possible work we can do to enable
- * saving and loading speech -- hardcoded binary data!
- */
- DECL_SYMBOL_ACTION(speech_machine_state)
- {
- char *str;
- if (task == csa_READ) {
- char tmp[2*(sizeof(sp)+sizeof(lpc))+1];
- if (iter)
- return 0;
- emulate_bin2hex((u8 *)&sp, tmp, sizeof(sp));
- command_arg_set_string(SYM_ARG_1st, tmp);
- emulate_bin2hex((u8 *)&lpc, tmp, sizeof(lpc));
- command_arg_set_string(SYM_ARG_2nd, tmp);
- return 1;
-
- }
-
- if (command_arg_get_string(SYM_ARG_1st, &str))
- emulate_hex2bin(str, (u8 *)&sp, sizeof(sp));
-
- if (command_arg_get_string(SYM_ARG_2nd, &str))
- emulate_hex2bin(str, (u8 *)&lpc, sizeof(lpc));
-
- // we have to restart speech if necessary,
- // since it's nearly impossible to reset the speech
- // synthesizer if it was in direct mode without
- // setting the timeout function.
- in_speech_intr = 0;
- if (sp.timeout && (sp.gate & GT_WDAT)) {
- SpeechOn();
- } else {
- sp.timeout = 0;
- }
- return 1;
- }
-
- /*************************************/
-