home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / speech.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  19.0 KB  |  925 lines

  1.  
  2. /*
  3.         SPEECH.C
  4.         =======
  5.  
  6. */
  7.  
  8. #define __SPEECH__
  9.  
  10. #include <unistd.h>
  11. #include "v9t9_common.h"
  12. #include "v9t9.h"
  13. #include "sound.h"
  14. #include "memory.h"
  15. #include "speech.h"
  16. #include "timer.h"
  17. #include "roms.h"
  18.  
  19. #define _L     LOG_SPEECH | LOG_INFO
  20. #include "tms5220r.c"
  21.  
  22. char    speechromfilename[64]="spchrom.bin";
  23.  
  24. static struct tms5200 sp;
  25. static struct LPC lpc;        /* LPC info */
  26.  
  27. u8         speechrom[65536];
  28.  
  29. static int speech_hertz = 8000;
  30. static int speech_length = 200;
  31. static s8 *speech_data;
  32.  
  33.  
  34. /****************************************************/
  35.  
  36. static int  speech_event_tag;
  37. static int  in_speech_intr = 0;    // mutex on speech_intr
  38.  
  39. #define SPEECH_TIMEOUT (25+9)
  40.  
  41. /****************************************************/
  42.  
  43.  
  44. static u8   swapped_nybbles[16] = 
  45.     0x0, 0x8, 0x4, 0xc,
  46.     0x2, 0xa, 0x6, 0xe,
  47.     0x1, 0x9, 0x5, 0xd,
  48.     0x3, 0xb, 0x7, 0xf
  49. };
  50.  
  51. static      u8
  52. swapbits(u8 in)
  53. {
  54.     return (swapped_nybbles[in & 0xf] << 4) |
  55.         (swapped_nybbles[(in & 0xf0) >> 4]);
  56. }
  57.  
  58. /*
  59. static u8
  60. swapbits(u8 in)
  61. {
  62.     in = ((in >> 1) & 0x55) | ((in << 1) & 0xaa);
  63.     in = ((in >> 2) & 0x33) | ((in << 2) & 0xcc);
  64.     in = ((in >> 4) & 0x0f) | ((in << 4) & 0xf0);
  65.     return in;
  66. }
  67. */
  68.  
  69. /******************************************************/
  70.  
  71. static void 
  72. tms5200purgeFIFO(void)
  73. {
  74.     sp.bit = sp.bits = sp.out = sp.in = sp.len = 0;
  75. }
  76.  
  77. static void
  78. LPCinit(void)
  79. {
  80.     memset((void *) &lpc, 0, sizeof(lpc));
  81.     lpc.decode |= FL_first;
  82.     /*  Reset excitation filters  */
  83.     lpc.ns1 = 0xaaaaaaaa;
  84.     lpc.ns2 = 0x1;
  85. }
  86.  
  87. static void
  88. SpeechOn(void)
  89. {
  90.     if (!speech_event_tag)
  91.         speech_event_tag = TM_UniqueTag();
  92.  
  93.     TM_SetEvent(speech_event_tag, TM_HZ * 100 / 40, 0,
  94.                 TM_REPEAT | TM_FUNC, speech_intr);
  95. }
  96.  
  97. static void
  98. SpeechOff(void)
  99. {
  100.     TM_ResetEvent(speech_event_tag);
  101. }
  102.  
  103. static void
  104. tms5200reset(void)
  105. {
  106.     logger(_L | L_1, "Speech reset");
  107.     sp.status = SS_BE | SS_BL;
  108.     tms5200purgeFIFO();
  109.     sp.command = 0x70;
  110.     sp.data = 0;
  111.     sp.addr = 0; sp.addr_pos = 0;
  112.     sp.gate = GT_RSTAT | GT_WCMD;
  113.     SpeechOff();
  114.     sp.status &= ~SS_SPEAKING;
  115.     sp.timeout = SPEECH_TIMEOUT;
  116.     LPCinit();
  117.     in_speech_intr = 0;
  118. }
  119.  
  120. static      u8
  121. tms5200read(void)
  122. {
  123.     sp.addr_pos = 0;
  124.     if (sp.addr >= 32768)
  125.         sp.data = 0;
  126.     else
  127.         sp.data = speechrom[sp.addr];
  128.     sp.addr++;
  129.     sp.gate = (sp.gate & ~GT_RSTAT) | GT_RDAT;
  130.     logger(_L | L_2, "Speech read: %02X\n\n", sp.data);
  131.     return sp.data;
  132. }
  133.  
  134. static      u8
  135. tms5200peek(void)
  136. {
  137.     sp.addr_pos = 0;
  138.     if (sp.addr >= 32768)
  139.         sp.data = 0;
  140.     else
  141.         sp.data = speechrom[sp.addr];
  142.     sp.gate = (sp.gate & ~GT_RSTAT) | GT_RDAT;
  143.     return sp.data;
  144. }
  145.  
  146. static void
  147. tms5200loadAddress(u32 nybble)
  148. {
  149.     sp.addr_pos = (sp.addr_pos + 1) % 5;
  150.     sp.addr = (sp.addr >> 4) | (nybble << 16);
  151.     logger(_L | L_2, "Speech addr = %04X\n", sp.addr);
  152. }
  153.  
  154. static void
  155. tms5200readAndBranch(void)
  156. {
  157.     u32         addr;
  158.  
  159.     sp.addr_pos = 0;
  160.     addr = (tms5200read() << 8) + tms5200read();
  161.     sp.addr = (sp.addr & 0xc000) | (addr & 0x3fff);
  162.     sp.gate = (sp.gate & ~GT_RDAT) | GT_RSTAT;
  163. }
  164.  
  165. static void
  166. tms5200speak(void)
  167. {
  168.     logger(_L | L_1, "Speaking phrase at %04X\n", sp.addr);
  169.     sp.status |= SS_TS;
  170.     sp.gate = (sp.gate & ~GT_WDAT) | GT_WCMD;    /* just in case */
  171.     sp.bit = 0;                    /* start on byte boundary */
  172.     // flush existing sample
  173.     SPEECHPLAY(vms_Speech, NULL, 0L, speech_hertz);
  174.     sp.status |= SS_SPEAKING;
  175.     while (sp.status & SS_SPEAKING)
  176.         speech_intr();            // not scheduled
  177.     LPCinit();
  178. }
  179.  
  180. static void
  181. tms5200speakExternal(void)
  182. {
  183.     logger(_L | L_1, "Speaking external data");
  184.     sp.gate = (sp.gate & ~GT_WCMD) | GT_WDAT;    /* accept data from I/O */
  185.     tms5200purgeFIFO();
  186.     SpeechOn();                    /* call speech_intr every 25 ms */
  187.     sp.status |= SS_SPEAKING;
  188.     sp.timeout = SPEECH_TIMEOUT;
  189. }
  190.  
  191. /*    Undocumented and unknown function... */
  192. static void
  193. tms5200loadFrameRate(u8 val)
  194. {
  195.     if (val & 0x4) {
  196.         /* variable */
  197.     } else {
  198.         /* frameRate = val & 0x3; */
  199.     }
  200. }
  201.  
  202. static void
  203. tms5200command(u8 cmd)
  204. {
  205.     sp.command = cmd & 0x70;
  206.     logger(_L | L_3, "Cmd=%02X  Status: %02X\n\n", cmd, sp.status);
  207.     switch (sp.command) {
  208.     case 0x00:
  209.     case 0x20:
  210.         tms5200loadFrameRate(cmd & 0x7);
  211.         break;
  212.     case 0x10:
  213.         tms5200read();
  214.         break;
  215.     case 0x30:
  216.         tms5200readAndBranch();
  217.         break;
  218.     case 0x40:
  219.         tms5200loadAddress(cmd & 0xf);
  220.         break;
  221.     case 0x50:
  222.         tms5200speak();
  223.         break;
  224.     case 0x60:
  225.         tms5200speakExternal();
  226.         break;
  227.     case 0x70:
  228.         tms5200reset();
  229.         break;
  230.         /* default: ignore */
  231.     }
  232. }
  233.  
  234. static void
  235. tms5200writeFIFO(u8 val)
  236. {
  237.     sp.fifo[sp.in] = swapbits(val);
  238.     sp.in = (sp.in + 1) & 15;
  239.     logger(_L | L_3, "FIFO write: %02X  len=%d\n", val, sp.len);
  240.     if (sp.len < 16)
  241.         sp.len++;
  242.     sp.timeout = SPEECH_TIMEOUT;
  243.     sp.status &= ~SS_BE;
  244.     if (sp.len > 8) {
  245.         sp.status &= ~SS_BL;
  246.         speech_intr();
  247.     }
  248. }
  249.  
  250. static      u8
  251. tms5200readFIFO(void)
  252. {
  253.     u8          ret = sp.fifo[sp.out];
  254.  
  255.     logger(_L | L_3, "FIFO read: %02X  len=%d\n", ret, sp.len);
  256.  
  257.     if (sp.len == 0) {
  258.         sp.status |= SS_BE;
  259.         tms5200reset();
  260.         SpeechOff();
  261.         logger(_L | L_1, "Speech timed out\n");
  262.     }
  263.  
  264.     if (sp.len > 0) {
  265.         sp.out = (sp.out + 1) & 15;
  266.         sp.len--;
  267.     }
  268.     if (sp.len < 8)
  269.         sp.status |= SS_BL;
  270.     if (sp.len == 0) {
  271.         sp.status |= SS_BE;
  272.     }
  273.     return ret;
  274. }
  275.  
  276. static      u8
  277. tms5200peekFIFO(void)
  278. {
  279.     return sp.fifo[sp.out];
  280. }
  281.  
  282.  
  283. /*
  284.     Fetch so many bits.
  285.     
  286.     This differs if we're reading from vocabulary or FIFO, in terms
  287.     of where a byte comes from, but that's all.
  288.     
  289.     When reading from the FIFO, we only execute ...readFIFO when we
  290.     are finished with the byte.
  291. */
  292. static      u32
  293. LPCfetch(int bits)
  294. {
  295.     u32         cur;
  296.  
  297.     if (sp.gate & GT_WDAT) {    /* from FIFO */
  298.         if (sp.bit + bits >= 8) {    /* we will cross into the next byte */
  299.             cur = tms5200readFIFO() << 8;
  300.             cur |= tms5200peekFIFO();    /* we can't read more than 6 bits,
  301.                                            so no poss of crossing TWO bytes */
  302.         } else
  303.             cur = tms5200peekFIFO() << 8;
  304.     } else {                    /* from vocab */
  305.  
  306.         if (sp.bit + bits >= 8) {
  307.             cur = tms5200read() << 8;
  308.             cur |= tms5200peek();
  309.         } else
  310.             cur = tms5200peek() << 8;
  311.     }
  312.  
  313.     /*  Get the bits we want.  */
  314.     cur = (cur << (sp.bit + 16)) >> (32 - bits);
  315.  
  316.     /*  Adjust bit ptr  */
  317.     sp.bit = (sp.bit + bits) & 7;
  318.  
  319.     sp.bits += bits;
  320.     return cur;
  321. }
  322.  
  323.  
  324. /***************************************************************
  325.     This section handles decoding one LPC equation into the 'lpc'
  326.     structure.
  327. ****************************************************************/
  328.  
  329. #define SHIFT 4
  330. #define KTRANS(x) (x)
  331.  
  332. static void
  333. LPCclearToSilence(void)
  334. {
  335.     lpc.pnv = 12;
  336.     lpc.env = 0;
  337.     memset(lpc.knv, 0, sizeof(lpc.knv));
  338.  
  339.     lpc.knv[0] = KTRANS(k1table[0]);
  340.     lpc.knv[1] = KTRANS(k2table[0]);
  341.     lpc.knv[2] = KTRANS(k3table[0]);
  342.     lpc.knv[3] = KTRANS(k4table[0]);
  343.     lpc.knv[4] = KTRANS(k5table[0]);
  344.     lpc.knv[5] = KTRANS(k6table[0]);
  345.     lpc.knv[6] = KTRANS(k7table[0]);
  346.     lpc.knv[7] = KTRANS(k8table[0]);
  347.     lpc.knv[8] = KTRANS(k9table[0]);
  348.     lpc.knv[9] = KTRANS(k10table[0]);
  349.     
  350.     // if the previous frame was unvoiced,
  351.     // it would sound bad to interpolate.
  352.     // just clear it all out.
  353.     if (lpc.decode & FL_unvoiced) {
  354.         lpc.pbf = 12;
  355.         lpc.ebf = 0;
  356.         memset(lpc.kbf, 0, sizeof(lpc.kbf));
  357.  
  358.         lpc.kbf[0] = KTRANS(k1table[0]);
  359.         lpc.kbf[1] = KTRANS(k2table[0]);
  360.         lpc.kbf[2] = KTRANS(k3table[0]);
  361.         lpc.kbf[3] = KTRANS(k4table[0]);
  362.         lpc.kbf[4] = KTRANS(k5table[0]);
  363.         lpc.kbf[5] = KTRANS(k6table[0]);
  364.         lpc.kbf[6] = KTRANS(k7table[0]);
  365.         lpc.kbf[7] = KTRANS(k8table[0]);
  366.         lpc.kbf[8] = KTRANS(k9table[0]);
  367.         lpc.kbf[9] = KTRANS(k10table[0]);
  368.     }
  369. }
  370.  
  371.  
  372. static void
  373. LPCreadEquation(void)
  374. {
  375.     char        txt[256], *tptr = txt;
  376.  
  377.     sp.bits = 0;
  378.  
  379.     /*     Copy now-old 'new' values into 'buffer' values */
  380.     lpc.ebf = lpc.env;
  381.     lpc.pbf = lpc.pnv;
  382.     memcpy(lpc.kbf, lpc.knv, sizeof(lpc.kbf));
  383.  
  384.     /*  Read energy  */
  385.     lpc.env = LPCfetch(4);
  386.     tptr += sprintf(tptr, "E: %d ", lpc.env);
  387.     if (lpc.env == 15) {
  388.         lpc.decode |= FL_last;
  389.         sp.status &= ~SS_TS;    /* we will go one more frame to 
  390.                                    interpolate to silence, then speech_event
  391.                                    will be reset */
  392.     } else if (lpc.env == 0) {    /* silent frame */
  393.         LPCclearToSilence();    /* clear params */
  394.         lpc.decode |= FL_nointerp;
  395.     } else {
  396.         /*  Repeat bit  */
  397.         lpc.rpt = LPCfetch(1);
  398.         tptr += sprintf(tptr, "R: %d ", lpc.rpt);
  399.  
  400.         /*  Pitch code  */
  401.         lpc.pnv = LPCfetch(6);
  402.         tptr += sprintf(tptr, "P: %d ", lpc.pnv);
  403.  
  404.         if (lpc.pnv == 0) {        /* unvoiced */
  405.             if (lpc.decode & FL_unvoiced)    /* voiced before? */
  406.                 lpc.decode |= FL_nointerp;    /* don't interpolate */
  407.             else
  408.                 lpc.decode &= ~FL_nointerp;
  409.             lpc.decode |= FL_unvoiced;
  410.             lpc.pnv = 12;        /* set some pitch */
  411.  
  412.             if (lpc.ebf == 0)    /* previous frame silent? */
  413.                 lpc.decode |= FL_nointerp;
  414.         } else {                /* voiced */
  415.  
  416.             lpc.pnv = pitchtable[lpc.pnv] >> 8;
  417.  
  418.             if (lpc.decode & FL_unvoiced)    /* unvoiced before? */
  419.                 lpc.decode |= FL_nointerp;    /* don't interpolate */
  420.             else
  421.                 lpc.decode &= ~FL_nointerp;
  422.  
  423.             lpc.decode &= ~FL_unvoiced;
  424.         }
  425.  
  426.         /* translate energy */
  427.         lpc.env = energytable[lpc.env];
  428.  
  429.         /*  Get K parameters  */
  430.  
  431.         if (!lpc.rpt) {            /* don't repeat previous frame? */
  432.             u32         tmp;
  433.  
  434.             tmp = LPCfetch(5);
  435.             lpc.knv[0] = KTRANS(k1table[tmp]);
  436.             tptr += sprintf(tptr, "K0: %d ", tmp);
  437.  
  438.             tmp = LPCfetch(5);
  439.             lpc.knv[1] = KTRANS(k2table[tmp]);
  440.             tptr += sprintf(tptr, "K1: %d ", tmp);
  441.  
  442.             tmp = LPCfetch(4);
  443.             lpc.knv[2] = KTRANS(k3table[tmp]);
  444.             tptr += sprintf(tptr, "K2: %d ", tmp);
  445.  
  446.             tmp = LPCfetch(4);
  447.             lpc.knv[3] = KTRANS(k4table[tmp]);
  448.             tptr += sprintf(tptr, "K3: %d ", tmp);
  449.  
  450.             if (!(lpc.decode & FL_unvoiced)) {    /* unvoiced? */
  451.                 tmp = LPCfetch(4);
  452.                 lpc.knv[4] = KTRANS(k5table[tmp]);
  453.                 tptr += sprintf(tptr, "K4: %d ", tmp);
  454.  
  455.                 tmp = LPCfetch(4);
  456.                 lpc.knv[5] = KTRANS(k6table[tmp]);
  457.                 tptr += sprintf(tptr, "K5: %d ", tmp);
  458.  
  459.                 tmp = LPCfetch(4);
  460.                 lpc.knv[6] = KTRANS(k7table[tmp]);
  461.                 tptr += sprintf(tptr, "K6: %d ", tmp);
  462.  
  463.                 tmp = LPCfetch(3);
  464.                 lpc.knv[7] = KTRANS(k8table[tmp]);
  465.                 tptr += sprintf(tptr, "K7: %d ", tmp);
  466.  
  467.                 tmp = LPCfetch(3);
  468.                 lpc.knv[8] = KTRANS(k9table[tmp]);
  469.  
  470.                 tptr += sprintf(tptr, "K8: %d ", tmp);
  471.  
  472.                 tmp = LPCfetch(3);
  473.                 lpc.knv[9] = KTRANS(k10table[tmp]);
  474.                 tptr += sprintf(tptr, "K9: %d ", tmp);
  475.             } else {
  476.                 lpc.knv[4] = KTRANS(k5table[0]);
  477.                 lpc.knv[5] = KTRANS(k6table[0]);
  478.                 lpc.knv[6] = KTRANS(k7table[0]);
  479.                 lpc.knv[7] = KTRANS(k8table[0]);
  480.                 lpc.knv[8] = KTRANS(k9table[0]);
  481.                 lpc.knv[9] = KTRANS(k10table[0]);
  482.             }
  483.         }
  484.     }
  485.     logger(_L | L_1, "Equation: %s\n", txt);
  486.  
  487.     logger(_L | L_1, "ebf=%d, pbf=%d, env=%d, pnv=%d\n",
  488.            lpc.ebf, lpc.pbf, lpc.env, lpc.pnv);
  489. }
  490.  
  491. /*******************************************************************
  492.     This section handles the 'execution' of an LPC equation.
  493. ********************************************************************/
  494.  
  495. /*
  496.     Interpolate "new" values and "buffer" values.
  497. */
  498. static void
  499. LPCinterpolate(int period)
  500. {
  501.     int         x;
  502.  
  503.     if (!(lpc.decode & FL_nointerp)) {
  504.         lpc.ebf += (lpc.env - lpc.ebf) / interp_coeff[period];
  505.         lpc.pbf += (lpc.pnv - lpc.pbf) / interp_coeff[period];
  506.         for (x = 0; x < 11; x++)
  507.             lpc.kbf[x] += (lpc.knv[x] - lpc.kbf[x]) / interp_coeff[period];
  508.     }
  509. /*    logger(_L|LOG_USER, "[%d]\n", lpc.kbf[0]);
  510.     if (period == 7) logger(_L|LOG_USER,"\n");*/
  511.  
  512.     logger(_L|L_1, "[%d] ebf=%d, pbf=%d\n", period, lpc.ebf, lpc.pbf);
  513. }
  514.  
  515. #define ONE 32768
  516.  
  517. // this is safe since our values are ~14 bits
  518. #define MD(a,b) (((a)*(b))/ONE)
  519. #define B(i) lpc.b[i]
  520. #define Y(i) lpc.y[i]
  521. #define K(i) lpc.kbf[i]
  522. #define U Y(10)
  523.  
  524. static void
  525. LPCcalc(void)
  526. {
  527.     int         frames, bytes, stage;
  528.     s8         *ptr;
  529.  
  530.     ptr = speech_data;
  531.     if (!ptr) 
  532.         return;
  533.  
  534.     frames = 8;
  535.     while (frames--) {
  536.         bytes = speech_length / 8;
  537.  
  538.         while (bytes--) {
  539.             s32         samp;
  540.  
  541.             /*  Get excitation data in U */
  542.             if ((lpc.decode & FL_unvoiced)) {
  543.                 U = (lpc.ns1 & 1) ? lpc.ebf / 4 : -lpc.ebf / 4;
  544.  
  545.                 /* noise generator */
  546.                 lpc.ns1 = (lpc.ns1 << 1) | (lpc.ns1 >> 31);
  547.                 lpc.ns1 ^= lpc.ns2;
  548.                 if ((lpc.ns2 += lpc.ns1) == 0)
  549.                     lpc.ns2++;
  550.             } else {
  551.                 U =
  552.                     lpc.ppctr <    41 
  553.                     ? chirptable[lpc.ppctr] * lpc.ebf / 256 
  554.                     : 0;
  555.                 if (lpc.pbf)
  556.                     lpc.ppctr = (lpc.ppctr + 1) % lpc.pbf;
  557.                 else
  558.                     lpc.ppctr = 0;
  559.             }
  560.  
  561.             /*  -----------------------------------------
  562.                10-stage lattice filter.
  563.  
  564.                range 1..10 here, 0..9 in our arrays
  565.  
  566.                Y10(i) = U(i) - K10*B10(i-1) U(i)=excitation
  567.                ----
  568.                Y9(i) = Y10(i) - K9*B9(i-1)
  569.                B10(i)= B9(i-1) + K9*Y9(i)
  570.                ----
  571.                ...
  572.                Y1(i) = Y2(i) - K1*B1(i-1)
  573.                B2(i) = B1(i-1) + K1*Y1(i)
  574.                ----
  575.                B1(i) = Y1(i)
  576.                ----------------------------------------- */
  577.  
  578.             /*  Stage 10 is different than the others.
  579.                Instead of calculating B11, we scale the excitation by
  580.                the energy.
  581.  
  582.              */
  583.  
  584.             for (stage = 9; stage >= 0; stage--) {
  585.                 Y(stage) = Y(stage + 1) - MD(K(stage), B(stage));
  586.                 B(stage + 1) = B(stage) + MD(K(stage), Y(stage));
  587.             }
  588.  
  589.             samp = Y(0);
  590.             B(0) = samp;
  591.  
  592.             *ptr++ = (samp > 511 ? 127 : samp < -512 ? -128 : samp >> 2);
  593.         }
  594.  
  595.         /* Interpolate values from *nv to *bf */
  596.         LPCinterpolate(7 - frames);
  597.     }
  598. }
  599.  
  600.  
  601. /*
  602.     Interpolation here is from the previous LPC equation.
  603.     Another 8 rounds of parameter interpolation occur inside
  604.     the calculation.
  605. */
  606. static void
  607. LPCexec(void)
  608. {
  609.     if (lpc.decode & (FL_nointerp | FL_first))
  610.         lpc.decode &= ~FL_first;
  611.  
  612.     lpc.ppctr = 0;
  613.  
  614.     memset(lpc.y, 0, sizeof(lpc.y));
  615.     memset(lpc.b, 0, sizeof(lpc.b));
  616.  
  617.     LPCcalc();
  618.  
  619.         /* spit it out */
  620.     if (speech_data)
  621.         SPEECHPLAY(vms_Speech, speech_data, speech_length, speech_hertz);    
  622.  
  623.     if (lpc.decode & FL_last) {    /* last frame */
  624.         logger(_L | L_1, "Done with speech phrase\n");
  625.         SpeechOff();            /* stop interrupting */
  626.         sp.status &= ~SS_SPEAKING;    /* stop interrupting */
  627.         sp.gate = (sp.gate & ~GT_WDAT) | GT_WCMD;
  628.     }
  629. }
  630.  
  631. /*    
  632.     One LPC frame consists of decoding one equation (or repeating,
  633.     or stopping), and calculating a speech waveform and outputting it.
  634.     
  635.     This happens during an interrupt.
  636.     
  637.     If we're here, we have enough data to form any one equation.
  638. */
  639. static void
  640. LPCframe(void)
  641. {
  642.     LPCreadEquation();
  643.     if (sp.status & SS_SPEAKING)    /* didn't get empty condition */
  644.         LPCexec();
  645. }
  646.  
  647.  
  648.  
  649. void
  650. speech_intr(void)
  651. {
  652.     if (in_speech_intr)
  653.         return;
  654.     in_speech_intr = 1;
  655.  
  656.     logger(_L | L_2, "In speech Interrupt\n");
  657.     if (sp.gate & GT_WDAT) {    /* direct data */
  658.         if (!(sp.status & SS_TS))    /* not talking yet... we're waiting for */
  659.             if (sp.status & SS_BL)    /* enough data in the buffer */
  660.                 goto out;        /* ... not yet */
  661.             else
  662.                 sp.status |= SS_TS;    /* whee!  Start talking */
  663.         else if (sp.status & SS_BL) {
  664.             if (sp.timeout-- <= 0)
  665.                 tms5200reset();
  666.             goto out;
  667.         }
  668.     }
  669.     LPCframe();                    /* execute a frame */
  670.   out:
  671.     logger(_L | L_2, "Out of speech interrupt\n");
  672.     in_speech_intr = 0;
  673. }
  674.  
  675.  
  676. /********************/
  677.  
  678. u16
  679. speech_mmio_get_addr(void)
  680. {
  681.     return sp.addr;
  682. }
  683.  
  684. void
  685. speech_mmio_set_addr(u16 addr)
  686. {
  687.     sp.addr = addr;
  688. }
  689.  
  690. bool
  691. speech_mmio_addr_is_complete(void)
  692. {
  693.     return sp.addr_pos == 0 || sp.addr_pos == 5;
  694. }
  695.  
  696. void
  697. speech_mmio_write(u8 val)
  698. {
  699.     if (sp.gate & GT_WCMD)
  700.         tms5200command(val);
  701.     else
  702.         tms5200writeFIFO(val);
  703. }
  704.  
  705. s8 speech_mmio_read(void)
  706. {
  707.     if (sp.gate & GT_RSTAT) {
  708.         logger(_L | L_2, "Status: %02X\n\n", sp.status);
  709.         return sp.status & (SS_TS | SS_BE | SS_BL);
  710.     } else {
  711.         sp.gate = (sp.gate & ~GT_RDAT) | GT_RSTAT;
  712.         return sp.data;
  713.     }
  714. }
  715.  
  716. mrstruct speech_handler =
  717. {
  718.     speechrom, speechrom, 0L,        // cannot write
  719.     NULL, NULL,
  720.     NULL, NULL
  721. };
  722.  
  723. void
  724. speech_memory_init(void)
  725. {
  726.     memory_insert_new_entry(MEMENT_SPEECH, 0x0000, 0x10000, 
  727.                            "Speech ROM",
  728.                             //    0L /*filename*/, 0L /*fileoffs*/, 
  729.                             speechromfilename, 0 /*fileoffs*/,
  730.                             &speech_handler);
  731.  
  732. }
  733.  
  734. /************************/
  735.  
  736. static void
  737. speech_initLPC(void)
  738. {
  739.     if (!(features & FE_SPEECH)) {
  740.         features &= ~(FE_PLAYSPEECH | FE_SPEECH);
  741.         logger(_L | LOG_USER, "Sound module cannot play speech, speech disabled.\n\n");
  742.     } else
  743.         logger(_L | L_0, "Setting up LPC speech...\n\n");
  744. }
  745.  
  746.  
  747. /***********************************************/
  748.  
  749. static
  750. DECL_SYMBOL_ACTION(speech_set_sample_length)
  751. {
  752.     if (task == csa_WRITE) {
  753.         xfree(speech_data);
  754.         if (speech_length <= 0) speech_length = 1;
  755.         speech_data = (s8*) xmalloc(speech_length);
  756.     }
  757.     return 1;
  758. }
  759.  
  760. static
  761. DECL_SYMBOL_ACTION(speech_define_speech_rom)
  762. {
  763.     char cmdbuf[1024];
  764.     char *fname;
  765.  
  766.     if (task == csa_READ) {
  767.         command_arg_get_string(SYM_ARG_1st, &fname);
  768.         if (!fname || !*fname)
  769.             return 0;
  770.         else 
  771.             return (iter == 0);
  772.     }
  773.  
  774.     command_arg_get_string(SYM_ARG_1st, &fname);
  775.     if (!*fname)
  776.         fname = "spchrom.bin";
  777.     sprintf(cmdbuf, "DefineMemory \"RS\" 0x0000 -0x10000 \"%s\" 0x0 \"Speech ROM\"\n", fname);
  778.     return command_parse_text(cmdbuf);
  779. }
  780.  
  781. int
  782. speech_preconfiginit(void)
  783. {
  784.     command_symbol_table *speechcommands =
  785.         command_symbol_table_new("Speech Options",
  786.                                  "These are commands for controlling speech synthesis",
  787.  
  788.          command_symbol_new("PlaySpeech",
  789.                             "Control whether speech is played",
  790.                             c_STATIC,
  791.                             NULL /*action*/,
  792.                             RET_FIRST_ARG,
  793.                             command_arg_new_toggle
  794.                             ("on|off",
  795.                              "toggle speech on or off",
  796.                              NULL /* action */ ,
  797.                              ARG_NUM(features),
  798.                              FE_PLAYSPEECH,
  799.                              NULL /* next */ )
  800.                             ,
  801.  
  802.          command_symbol_new("SpeechROMFileName",
  803.                             "Name of speech ROM",
  804.                             c_DYNAMIC,
  805.                             speech_define_speech_rom /* action */ ,
  806.                             RET_FIRST_ARG,
  807.                             command_arg_new_string
  808.                             ("file",
  809.                              "name of binary image",
  810.                              NULL /* action */,
  811.                              NEW_ARG_NEW_STRBUF,
  812.                              NULL /* next */ )
  813.                             ,
  814.  
  815.          command_symbol_new("SpeechHertz",
  816.                             "Set sample rate for speech",
  817.                             c_STATIC,
  818.                             NULL /*action*/,
  819.                             RET_FIRST_ARG,
  820.                             command_arg_new_num
  821.                             ("hertz",
  822.                              "normal value is 8000",
  823.                              NULL /* action */ ,
  824.                              ARG_NUM(speech_hertz),
  825.                              NULL /* next */ )
  826.                             ,
  827.  
  828.          command_symbol_new("SpeechSampleLength",
  829.                             "Set sample length for a unit of speech",
  830.                             c_STATIC,
  831.                             speech_set_sample_length,
  832.                             RET_FIRST_ARG,
  833.                             command_arg_new_num
  834.                             ("length",
  835.                              "in bytes, normal value is 200",
  836.                              NULL /* action */ ,
  837.                              ARG_NUM(speech_length),
  838.                              NULL /* next */ )
  839.                             ,
  840.  
  841.         NULL /*next*/)))),
  842.         NULL /*sub*/,
  843.         NULL /*next*/
  844.     );                                 
  845.  
  846.     command_symbol_table_add_subtable(universe, speechcommands);
  847.     speech_length = 200;
  848.     speech_data = (s8*) xmalloc(speech_length);
  849.     LPCinit();
  850.     features |= FE_SPEECH|FE_PLAYSPEECH;
  851.     return 1;
  852. }
  853.  
  854. int
  855. speech_postconfiginit(void)
  856. {
  857. /*    if (!loadspeech(romspath, systemromspath, 
  858.                     speechromfilename, speechrom)) {
  859.           features &= ~FE_PLAYSPEECH;
  860.     }
  861. */
  862.     speech_memory_init();
  863.     speech_initLPC();
  864.     tms5200reset();
  865.     return 1;
  866. }
  867.  
  868. int
  869. speech_restart(void)
  870. {
  871.     return 1;
  872. }
  873.  
  874. void
  875. speech_restop(void)
  876. {
  877. }
  878.  
  879. void
  880. speech_shutdown(void)
  881. {
  882.     xfree(speech_data);
  883. }
  884.  
  885. /*
  886.  *    The least possible work we can do to enable
  887.  *    saving and loading speech -- hardcoded binary data!
  888.  */
  889. DECL_SYMBOL_ACTION(speech_machine_state)
  890. {
  891.     char *str;
  892.     if (task == csa_READ) {
  893.         char tmp[2*(sizeof(sp)+sizeof(lpc))+1];
  894.         if (iter)
  895.             return 0;
  896.         emulate_bin2hex((u8 *)&sp, tmp, sizeof(sp));
  897.         command_arg_set_string(SYM_ARG_1st, tmp);
  898.         emulate_bin2hex((u8 *)&lpc, tmp, sizeof(lpc));
  899.         command_arg_set_string(SYM_ARG_2nd, tmp);
  900.         return 1;
  901.  
  902.     }
  903.  
  904.     if (command_arg_get_string(SYM_ARG_1st, &str))
  905.         emulate_hex2bin(str, (u8 *)&sp, sizeof(sp));
  906.  
  907.     if (command_arg_get_string(SYM_ARG_2nd, &str))
  908.         emulate_hex2bin(str, (u8 *)&lpc, sizeof(lpc));
  909.  
  910.     // we have to restart speech if necessary,
  911.     // since it's nearly impossible to reset the speech
  912.     // synthesizer if it was in direct mode without
  913.     // setting the timeout function.
  914.     in_speech_intr = 0;
  915.     if (sp.timeout && (sp.gate & GT_WDAT)) {
  916.         SpeechOn();
  917.     } else {
  918.         sp.timeout = 0;
  919.     }
  920.     return 1;
  921. }
  922.  
  923. /*************************************/
  924.