diff --git a/applications/plugins/sam/application.fam b/applications/plugins/sam/application.fam new file mode 100644 index 000000000..ee11b722e --- /dev/null +++ b/applications/plugins/sam/application.fam @@ -0,0 +1,14 @@ +App( + appid="SAM", + name="SAM", + apptype=FlipperAppType.PLUGIN, + entry_point="sam_app", + requires=[ + "gui", + "dialogs", + ], + stack_size=4 * 1024, + order=20, + fap_icon="../../assets/icons/Archive/music_10px.png", + fap_category="Misc", +) diff --git a/applications/plugins/sam/sam_app.cpp b/applications/plugins/sam/sam_app.cpp new file mode 100644 index 000000000..588cddbd0 --- /dev/null +++ b/applications/plugins/sam/sam_app.cpp @@ -0,0 +1,13 @@ +#include +#include "stm32_sam.h" + +STM32SAM voice; + +extern "C" int32_t sam_app(void* p) { + UNUSED(p); + + voice.begin(); + voice.say("Hello world. I am FLIPPER SAM, automated voice!"); + + return 0; +} \ No newline at end of file diff --git a/applications/plugins/sam/stm32_sam.cpp b/applications/plugins/sam/stm32_sam.cpp new file mode 100644 index 000000000..16f6fcaab --- /dev/null +++ b/applications/plugins/sam/stm32_sam.cpp @@ -0,0 +1,5704 @@ + +#include "stm32_sam.h" +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// All +// +//////////////////////////////////////////////////////////////////////////////////////////// + +char input[256 + 1] = {0}; //tab39445 +//standard sam sound + +unsigned char wait1 = 7; +unsigned char wait2 = 6; + +unsigned char A, X, Y; +unsigned char mem44; +unsigned char mem47; +unsigned char mem49; +unsigned char mem39; +unsigned char mem50; +unsigned char mem51; +unsigned char mem53; +unsigned char mem56; +unsigned char mem59 = 0; + +unsigned char phonemeIndexOutput[60]; //tab47296 +unsigned char stressOutput[60]; //tab47365 +unsigned char phonemeLengthOutput[60]; //tab47416 + +// contains the soundbuffer position +int bufferpos; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Sam Tabs +// +//////////////////////////////////////////////////////////////////////////////////////////// + +//tab40672 +const unsigned char stressInputTable[] = {'*', '1', '2', '3', '4', '5', '6', '7', '8'}; + +//tab40682 +const unsigned char signInputTable1[] = { + ' ', '.', '?', ',', '-', 'I', 'I', 'E', 'A', 'A', 'A', 'A', 'U', 'A', 'I', 'E', 'U', + 'O', 'R', 'L', 'W', 'Y', 'W', 'R', 'L', 'W', 'Y', 'M', 'N', 'N', 'D', 'Q', 'S', 'S', + 'F', 'T', '/', '/', 'Z', 'Z', 'V', 'D', 'C', '*', 'J', '*', '*', '*', 'E', 'A', 'O', + 'A', 'O', 'U', 'B', '*', '*', 'D', '*', '*', 'G', '*', '*', 'G', '*', '*', 'P', '*', + '*', 'T', '*', '*', 'K', '*', '*', 'K', '*', '*', 'U', 'U', 'U'}; + +//tab40763 +const unsigned char signInputTable2[] = { + '*', '*', '*', '*', '*', 'Y', 'H', 'H', 'E', 'A', 'H', 'O', 'H', 'X', 'X', 'R', 'X', + 'H', 'X', 'X', 'X', 'X', 'H', '*', '*', '*', '*', '*', '*', 'X', 'X', '*', '*', 'H', + '*', 'H', 'H', 'X', '*', 'H', '*', 'H', 'H', '*', '*', '*', '*', '*', 'Y', 'Y', 'Y', + 'W', 'W', 'W', '*', '*', '*', '*', '*', '*', '*', '*', '*', 'X', '*', '*', '*', '*', + '*', '*', '*', '*', '*', '*', '*', 'X', '*', '*', 'L', 'M', 'N'}; + +//loc_9F8C +const unsigned char flags[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0x84, 0x84, 0xA4, + 0xA4, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4C, + 0x4C, 0x4C, 0x48, 0x4C, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x44, 0x44, + 0x48, 0x40, 0x4C, 0x44, 0x00, 0x00, 0xB4, 0xB4, 0xB4, 0x94, 0x94, 0x94, 0x4E, 0x4E, + 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4B, 0x4B, 0x4B, 0x4B, + 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x80, 0xC1, 0xC1 + +}; + +//??? flags overlap flags2 +//loc_9FDA +const unsigned char flags2[] = { + 0x80, 0xC1, 0xC1, 0xC1, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0C, 0x08, 0x04, 0x40, + 0x24, 0x20, 0x20, 0x24, 0x00, 0x00, 0x24, 0x20, 0x20, 0x24, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +//tab45616??? +const unsigned char phonemeStressedLengthTable[] = { + 0x00, 0x12, 0x12, 0x12, 8, 0xB, 9, 0xB, 0xE, 0xF, 0xB, 0x10, 0xC, 6, 6, 0xE, + 0xC, 0xE, 0xC, 0xB, 8, 8, 0xB, 0xA, 9, 8, 8, 8, 8, 8, 3, 5, + 2, 2, 2, 2, 2, 2, 6, 6, 8, 6, 6, 2, 9, 4, 2, 1, + 0xE, 0xF, 0xF, 0xF, 0xE, 0xE, 8, 2, 2, 7, 2, 1, 7, 2, 2, 7, + 2, 2, 8, 2, 2, 6, 2, 2, 7, 2, 4, 7, 1, 4, 5, 5}; + +//tab45536??? +const unsigned char phonemeLengthTable[] = { + 0, 0x12, 0x12, 0x12, 8, 8, 8, 8, 8, 0xB, 6, 0xC, 0xA, 5, 5, 0xB, 0xA, 0xA, 0xA, 9, + 8, 7, 9, 7, 6, 8, 6, 7, 7, 7, 2, 5, 2, 2, 2, 2, 2, 2, 6, 6, + 7, 6, 6, 2, 8, 3, 1, 0x1E, 0xD, 0xC, 0xC, 0xC, 0xE, 9, 6, 1, 2, 5, 1, 1, + 6, 1, 2, 6, 1, 2, 8, 2, 2, 4, 2, 2, 6, 1, 4, 6, 1, 4, 0xC7, 0xFF}; + +/* + + Ind | phoneme | flags | + -----|---------|----------| + 0 | * | 00000000 | + 1 | .* | 00000000 | + 2 | ?* | 00000000 | + 3 | ,* | 00000000 | + 4 | -* | 00000000 | + + VOWELS + 5 | IY | 10100100 | + 6 | IH | 10100100 | + 7 | EH | 10100100 | + 8 | AE | 10100100 | + 9 | AA | 10100100 | + 10 | AH | 10100100 | + 11 | AO | 10000100 | + 17 | OH | 10000100 | + 12 | UH | 10000100 | + 16 | UX | 10000100 | + 15 | ER | 10000100 | + 13 | AX | 10100100 | + 14 | IX | 10100100 | + + DIPHTONGS + 48 | EY | 10110100 | + 49 | AY | 10110100 | + 50 | OY | 10110100 | + 51 | AW | 10010100 | + 52 | OW | 10010100 | + 53 | UW | 10010100 | + + + 21 | YX | 10000100 | + 20 | WX | 10000100 | + 18 | RX | 10000100 | + 19 | LX | 10000100 | + 37 | /X | 01000000 | + 30 | DX | 01001000 | + + + 22 | WH | 01000100 | + + + VOICED CONSONANTS + 23 | R* | 01000100 | + 24 | L* | 01000100 | + 25 | W* | 01000100 | + 26 | Y* | 01000100 | + 27 | M* | 01001100 | + 28 | N* | 01001100 | + 29 | NX | 01001100 | + 54 | B* | 01001110 | + 57 | D* | 01001110 | + 60 | G* | 01001110 | + 44 | J* | 01001100 | + 38 | Z* | 01000100 | + 39 | ZH | 01000100 | + 40 | V* | 01000100 | + 41 | DH | 01000100 | + + unvoiced CONSONANTS + 32 | S* | 01000000 | + 33 | SH | 01000000 | + 34 | F* | 01000000 | + 35 | TH | 01000000 | + 66 | P* | 01001011 | + 69 | T* | 01001011 | + 72 | K* | 01001011 | + 42 | CH | 01001000 | + 36 | /H | 01000000 | + + 43 | ** | 01000000 | + 45 | ** | 01000100 | + 46 | ** | 00000000 | + 47 | ** | 00000000 | + + + 55 | ** | 01001110 | + 56 | ** | 01001110 | + 58 | ** | 01001110 | + 59 | ** | 01001110 | + 61 | ** | 01001110 | + 62 | ** | 01001110 | + 63 | GX | 01001110 | + 64 | ** | 01001110 | + 65 | ** | 01001110 | + 67 | ** | 01001011 | + 68 | ** | 01001011 | + 70 | ** | 01001011 | + 71 | ** | 01001011 | + 73 | ** | 01001011 | + 74 | ** | 01001011 | + 75 | KX | 01001011 | + 76 | ** | 01001011 | + 77 | ** | 01001011 | + + + SPECIAL + 78 | UL | 10000000 | + 79 | UM | 11000001 | + 80 | UN | 11000001 | + 31 | Q* | 01001100 | + +*/ + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// RenderTabs +// +//////////////////////////////////////////////////////////////////////////////////////////// + +const unsigned char tab48426[5] = {0x18, 0x1A, 0x17, 0x17, 0x17}; + +const unsigned char tab47492[] = {0, 0, 0xE0, 0xE6, 0xEC, 0xF3, 0xF9, 0, 6, 0xC, 6}; + +const unsigned char amplitudeRescale[] = { + 0, + 1, + 2, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 6, + 8, + 9, + 0xB, + 0xD, + 0xF, + 0 //17 elements? +}; + +// Used to decide which phoneme's blend lengths. The candidate with the lower score is selected. +// tab45856 +const unsigned char blendRank[] = {0, 0x1F, 0x1F, 0x1F, 0x1F, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 5, 5, 2, 0xA, 2, 8, + 5, 5, 0xB, 0xA, 9, 8, 8, 0xA0, 8, 8, + 0x17, 0x1F, 0x12, 0x12, 0x12, 0x12, 0x1E, 0x1E, 0x14, 0x14, + 0x14, 0x14, 0x17, 0x17, 0x1A, 0x1A, 0x1D, 0x1D, 2, 2, + 2, 2, 2, 2, 0x1A, 0x1D, 0x1B, 0x1A, 0x1D, 0x1B, + 0x1A, 0x1D, 0x1B, 0x1A, 0x1D, 0x1B, 0x17, 0x1D, 0x17, 0x17, + 0x1D, 0x17, 0x17, 0x1D, 0x17, 0x17, 0x1D, 0x17, 0x17, 0x17}; + +// Number of frames at the end of a phoneme devoted to interpolating to next phoneme's final value +//tab45696 +const unsigned char outBlendLength[] = {0, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 3, 2, 4, 4, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 0, 1, 0, 1, 0, 5, + 5, 5, 5, 5, 4, 4, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 2, 2, 0, 1, 3, 0, 2, 3, 0, 2, 0xA0, 0xA0}; + +// Number of frames at beginning of a phoneme devoted to interpolating to phoneme's final value +// tab45776 +const unsigned char inBlendLength[] = {0, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3, 1, 2, 3, 2, 1, + 3, 3, 3, 3, 1, 1, 3, 3, 3, 2, 2, 3, 2, 3, 0, 0, + 5, 5, 5, 5, 4, 4, 2, 0, 2, 2, 0, 3, 2, 0, 4, 2, + 0, 3, 2, 0, 2, 2, 0, 2, 3, 0, 3, 3, 0, 3, 0xB0, 0xA0}; + +// Looks like it's used as bit flags +// High bits masked by 248 (11111000) +// +// 32: S* 241 11110001 +// 33: SH 226 11100010 +// 34: F* 211 11010011 +// 35: TH 187 10111011 +// 36: /H 124 01111100 +// 37: /X 149 10010101 +// 38: Z* 1 00000001 +// 39: ZH 2 00000010 +// 40: V* 3 00000011 +// 41: DH 3 00000011 +// 43: ** 114 01110010 +// 45: ** 2 00000010 +// 67: ** 27 00011011 +// 70: ** 25 00011001 +// tab45936 +const unsigned char sampledConsonantFlags[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xF1, 0xE2, 0xD3, 0xBB, 0x7C, 0x95, 1, 2, + 3, 3, 0, 0x72, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x1B, 0, 0, 0x19, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +//tab45056 +unsigned char freq1data[] = { + 0x00, 0x13, 0x13, 0x13, 0x13, 0xA, 0xE, 0x12, 0x18, 0x1A, 0x16, 0x14, 0x10, 0x14, 0xE, 0x12, + 0xE, 0x12, 0x12, 0x10, 0xC, 0xE, 0xA, 0x12, 0xE, 0xA, 8, 6, 6, 6, 6, 0x11, + 6, 6, 6, 6, 0xE, 0x10, 9, 0xA, 8, 0xA, 6, 6, 6, 5, 6, 0, + 0x12, 0x1A, 0x14, 0x1A, 0x12, 0xC, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 0xA, 0xA, 6, 6, 6, 0x2C, 0x13}; + +//tab451356 +unsigned char freq2data[] = {0x00, 0x43, 0x43, 0x43, 0x43, 0x54, 0x48, 0x42, 0x3E, 0x28, + 0x2C, 0x1E, 0x24, 0x2C, 0x48, 0x30, 0x24, 0x1E, 0x32, 0x24, + 0x1C, 0x44, 0x18, 0x32, 0x1E, 0x18, 0x52, 0x2E, 0x36, 0x56, + 0x36, 0x43, 0x49, 0x4F, 0x1A, 0x42, 0x49, 0x25, 0x33, 0x42, + 0x28, 0x2F, 0x4F, 0x4F, 0x42, 0x4F, 0x6E, 0x00, 0x48, 0x26, + 0x1E, 0x2A, 0x1E, 0x22, 0x1A, 0x1A, 0x1A, 0x42, 0x42, 0x42, + 0x6E, 0x6E, 0x6E, 0x54, 0x54, 0x54, 0x1A, 0x1A, 0x1A, 0x42, + 0x42, 0x42, 0x6D, 0x56, 0x6D, 0x54, 0x54, 0x54, 0x7F, 0x7F}; +//tab45216 +unsigned char freq3data[] = {0x00, 0x5B, 0x5B, 0x5B, 0x5B, 0x6E, 0x5D, 0x5B, 0x58, 0x59, + 0x57, 0x58, 0x52, 0x59, 0x5D, 0x3E, 0x52, 0x58, 0x3E, 0x6E, + 0x50, 0x5D, 0x5A, 0x3C, 0x6E, 0x5A, 0x6E, 0x51, 0x79, 0x65, + 0x79, 0x5B, 0x63, 0x6A, 0x51, 0x79, 0x5D, 0x52, 0x5D, 0x67, + 0x4C, 0x5D, 0x65, 0x65, 0x79, 0x65, 0x79, 0x00, 0x5A, 0x58, + 0x58, 0x58, 0x58, 0x52, 0x51, 0x51, 0x51, 0x79, 0x79, 0x79, + 0x70, 0x6E, 0x6E, 0x5E, 0x5E, 0x5E, 0x51, 0x51, 0x51, 0x79, + 0x79, 0x79, 0x65, 0x65, 0x70, 0x5E, 0x5E, 0x5E, 0x08, 0x01}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Reciter +// +//////////////////////////////////////////////////////////////////////////////////////////// + +unsigned char inputtemp[256]; // secure copy of input tab36096 + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Render +// +//////////////////////////////////////////////////////////////////////////////////////////// + +//timetable for more accurate c64 simulation +int timetable[5][5] = { + {162, 167, 167, 127, 128}, + {226, 60, 60, 0, 0}, + {225, 60, 59, 0, 0}, + {200, 0, 0, 54, 55}, + {199, 0, 0, 54, 54}}; + +unsigned oldtimetableindex; + +const unsigned char ampl1data[] = {0, 0, 0, 0, 0, 0xD, 0xD, 0xE, 0xF, 0xF, 0xF, 0xF, + 0xF, 0xC, 0xD, 0xC, 0xF, 0xF, 0xD, 0xD, 0xD, 0xE, 0xD, 0xC, + 0xD, 0xD, 0xD, 0xC, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0xB, 0xB, 0xB, 0xB, 0, 0, 1, 0xB, 0, 2, + 0xE, 0xF, 0xF, 0xF, 0xF, 0xD, 2, 4, 0, 2, 4, 0, + 1, 4, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0xC, 0, 0, 0, 0, 0xF, 0xF}; + +const unsigned char ampl2data[] = { + 0, 0, 0, 0, 0, 0xA, 0xB, 0xD, 0xE, 0xD, 0xC, 0xC, 0xB, 9, 0xB, 0xB, 0xC, 0xC, 0xC, 8, + 8, 0xC, 8, 0xA, 8, 8, 0xA, 3, 9, 6, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, + 3, 4, 0, 0, 0, 5, 0xA, 2, 0xE, 0xD, 0xC, 0xD, 0xC, 8, 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0xA, 0, 0, 0xA, 0, 0, 0}; + +const unsigned char ampl3data[] = {0, 0, 0, 0, 0, 8, 7, 8, 8, 1, 1, 0, 1, 0, 7, 5, + 1, 0, 6, 1, 0, 7, 0, 5, 1, 0, 8, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0xE, 1, + 9, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 5, 0, 0x13, 0x10}; + +//tab42240 +const signed char sinus[256] = { + 0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, + 49, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88, + 90, 92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113, 115, 116, + 117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127, + 127, 127, 127, 127, 126, 126, 126, 125, 125, 124, 123, 122, 122, 121, 120, 118, + 117, 116, 115, 113, 112, 111, 109, 107, 106, 104, 102, 100, 98, 96, 94, 92, + 90, 88, 85, 83, 81, 78, 76, 73, 71, 68, 65, 63, 60, 57, 54, 51, + 49, 46, 43, 40, 37, 34, 31, 28, 25, 22, 19, 16, 12, 9, 6, 3, + 0, -3, -6, -9, -12, -16, -19, -22, -25, -28, -31, -34, -37, -40, -43, -46, + -49, -51, -54, -57, -60, -63, -65, -68, -71, -73, -76, -78, -81, -83, -85, -88, + -90, -92, -94, -96, -98, -100, -102, -104, -106, -107, -109, -111, -112, -113, -115, -116, + -117, -118, -120, -121, -122, -122, -123, -124, -125, -125, -126, -126, -126, -127, -127, -127, + -127, -127, -127, -127, -126, -126, -126, -125, -125, -124, -123, -122, -122, -121, -120, -118, + -117, -116, -115, -113, -112, -111, -109, -107, -106, -104, -102, -100, -98, -96, -94, -92, + -90, -88, -85, -83, -81, -78, -76, -73, -71, -68, -65, -63, -60, -57, -54, -51, + -49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -12, -9, -6, -3}; + +//tab42496 +const unsigned char rectangle[] = { + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70}; + +//random data ? +const unsigned char sampleTable[0x500] = { + //00 + + 0x38, + 0x84, + 0x6B, + 0x19, + 0xC6, + 0x63, + 0x18, + 0x86, + 0x73, + 0x98, + 0xC6, + 0xB1, + 0x1C, + 0xCA, + 0x31, + 0x8C, + 0xC7, + 0x31, + 0x88, + 0xC2, + 0x30, + 0x98, + 0x46, + 0x31, + 0x18, + 0xC6, + 0x35, + 0xC, + 0xCA, + 0x31, + 0xC, + 0xC6 + //20 + , + 0x21, + 0x10, + 0x24, + 0x69, + 0x12, + 0xC2, + 0x31, + 0x14, + 0xC4, + 0x71, + 8, + 0x4A, + 0x22, + 0x49, + 0xAB, + 0x6A, + 0xA8, + 0xAC, + 0x49, + 0x51, + 0x32, + 0xD5, + 0x52, + 0x88, + 0x93, + 0x6C, + 0x94, + 0x22, + 0x15, + 0x54, + 0xD2, + 0x25 + //40 + , + 0x96, + 0xD4, + 0x50, + 0xA5, + 0x46, + 0x21, + 8, + 0x85, + 0x6B, + 0x18, + 0xC4, + 0x63, + 0x10, + 0xCE, + 0x6B, + 0x18, + 0x8C, + 0x71, + 0x19, + 0x8C, + 0x63, + 0x35, + 0xC, + 0xC6, + 0x33, + 0x99, + 0xCC, + 0x6C, + 0xB5, + 0x4E, + 0xA2, + 0x99 + //60 + , + 0x46, + 0x21, + 0x28, + 0x82, + 0x95, + 0x2E, + 0xE3, + 0x30, + 0x9C, + 0xC5, + 0x30, + 0x9C, + 0xA2, + 0xB1, + 0x9C, + 0x67, + 0x31, + 0x88, + 0x66, + 0x59, + 0x2C, + 0x53, + 0x18, + 0x84, + 0x67, + 0x50, + 0xCA, + 0xE3, + 0xA, + 0xAC, + 0xAB, + 0x30 + //80 + , + 0xAC, + 0x62, + 0x30, + 0x8C, + 0x63, + 0x10, + 0x94, + 0x62, + 0xB1, + 0x8C, + 0x82, + 0x28, + 0x96, + 0x33, + 0x98, + 0xD6, + 0xB5, + 0x4C, + 0x62, + 0x29, + 0xA5, + 0x4A, + 0xB5, + 0x9C, + 0xC6, + 0x31, + 0x14, + 0xD6, + 0x38, + 0x9C, + 0x4B, + 0xB4 + //A0 + , + 0x86, + 0x65, + 0x18, + 0xAE, + 0x67, + 0x1C, + 0xA6, + 0x63, + 0x19, + 0x96, + 0x23, + 0x19, + 0x84, + 0x13, + 8, + 0xA6, + 0x52, + 0xAC, + 0xCA, + 0x22, + 0x89, + 0x6E, + 0xAB, + 0x19, + 0x8C, + 0x62, + 0x34, + 0xC4, + 0x62, + 0x19, + 0x86, + 0x63 + //C0 + , + 0x18, + 0xC4, + 0x23, + 0x58, + 0xD6, + 0xA3, + 0x50, + 0x42, + 0x54, + 0x4A, + 0xAD, + 0x4A, + 0x25, + 0x11, + 0x6B, + 0x64, + 0x89, + 0x4A, + 0x63, + 0x39, + 0x8A, + 0x23, + 0x31, + 0x2A, + 0xEA, + 0xA2, + 0xA9, + 0x44, + 0xC5, + 0x12, + 0xCD, + 0x42 + //E0 + , + 0x34, + 0x8C, + 0x62, + 0x18, + 0x8C, + 0x63, + 0x11, + 0x48, + 0x66, + 0x31, + 0x9D, + 0x44, + 0x33, + 0x1D, + 0x46, + 0x31, + 0x9C, + 0xC6, + 0xB1, + 0xC, + 0xCD, + 0x32, + 0x88, + 0xC4, + 0x73, + 0x18, + 0x86, + 0x73, + 8, + 0xD6, + 0x63, + 0x58 + //100 + , + 7, + 0x81, + 0xE0, + 0xF0, + 0x3C, + 7, + 0x87, + 0x90, + 0x3C, + 0x7C, + 0xF, + 0xC7, + 0xC0, + 0xC0, + 0xF0, + 0x7C, + 0x1E, + 7, + 0x80, + 0x80, + 0, + 0x1C, + 0x78, + 0x70, + 0xF1, + 0xC7, + 0x1F, + 0xC0, + 0xC, + 0xFE, + 0x1C, + 0x1F + //120 + , + 0x1F, + 0xE, + 0xA, + 0x7A, + 0xC0, + 0x71, + 0xF2, + 0x83, + 0x8F, + 3, + 0xF, + 0xF, + 0xC, + 0, + 0x79, + 0xF8, + 0x61, + 0xE0, + 0x43, + 0xF, + 0x83, + 0xE7, + 0x18, + 0xF9, + 0xC1, + 0x13, + 0xDA, + 0xE9, + 0x63, + 0x8F, + 0xF, + 0x83 + //140 + , + 0x83, + 0x87, + 0xC3, + 0x1F, + 0x3C, + 0x70, + 0xF0, + 0xE1, + 0xE1, + 0xE3, + 0x87, + 0xB8, + 0x71, + 0xE, + 0x20, + 0xE3, + 0x8D, + 0x48, + 0x78, + 0x1C, + 0x93, + 0x87, + 0x30, + 0xE1, + 0xC1, + 0xC1, + 0xE4, + 0x78, + 0x21, + 0x83, + 0x83, + 0xC3 + //160 + , + 0x87, + 6, + 0x39, + 0xE5, + 0xC3, + 0x87, + 7, + 0xE, + 0x1C, + 0x1C, + 0x70, + 0xF4, + 0x71, + 0x9C, + 0x60, + 0x36, + 0x32, + 0xC3, + 0x1E, + 0x3C, + 0xF3, + 0x8F, + 0xE, + 0x3C, + 0x70, + 0xE3, + 0xC7, + 0x8F, + 0xF, + 0xF, + 0xE, + 0x3C + //180 + , + 0x78, + 0xF0, + 0xE3, + 0x87, + 6, + 0xF0, + 0xE3, + 7, + 0xC1, + 0x99, + 0x87, + 0xF, + 0x18, + 0x78, + 0x70, + 0x70, + 0xFC, + 0xF3, + 0x10, + 0xB1, + 0x8C, + 0x8C, + 0x31, + 0x7C, + 0x70, + 0xE1, + 0x86, + 0x3C, + 0x64, + 0x6C, + 0xB0, + 0xE1 + //1A0 + , + 0xE3, + 0xF, + 0x23, + 0x8F, + 0xF, + 0x1E, + 0x3E, + 0x38, + 0x3C, + 0x38, + 0x7B, + 0x8F, + 7, + 0xE, + 0x3C, + 0xF4, + 0x17, + 0x1E, + 0x3C, + 0x78, + 0xF2, + 0x9E, + 0x72, + 0x49, + 0xE3, + 0x25, + 0x36, + 0x38, + 0x58, + 0x39, + 0xE2, + 0xDE + //1C0 + , + 0x3C, + 0x78, + 0x78, + 0xE1, + 0xC7, + 0x61, + 0xE1, + 0xE1, + 0xB0, + 0xF0, + 0xF0, + 0xC3, + 0xC7, + 0xE, + 0x38, + 0xC0, + 0xF0, + 0xCE, + 0x73, + 0x73, + 0x18, + 0x34, + 0xB0, + 0xE1, + 0xC7, + 0x8E, + 0x1C, + 0x3C, + 0xF8, + 0x38, + 0xF0, + 0xE1 + //1E0 + , + 0xC1, + 0x8B, + 0x86, + 0x8F, + 0x1C, + 0x78, + 0x70, + 0xF0, + 0x78, + 0xAC, + 0xB1, + 0x8F, + 0x39, + 0x31, + 0xDB, + 0x38, + 0x61, + 0xC3, + 0xE, + 0xE, + 0x38, + 0x78, + 0x73, + 0x17, + 0x1E, + 0x39, + 0x1E, + 0x38, + 0x64, + 0xE1, + 0xF1, + 0xC1 + //200 + , + 0x4E, + 0xF, + 0x40, + 0xA2, + 2, + 0xC5, + 0x8F, + 0x81, + 0xA1, + 0xFC, + 0x12, + 8, + 0x64, + 0xE0, + 0x3C, + 0x22, + 0xE0, + 0x45, + 7, + 0x8E, + 0xC, + 0x32, + 0x90, + 0xF0, + 0x1F, + 0x20, + 0x49, + 0xE0, + 0xF8, + 0xC, + 0x60, + 0xF0 + //220 + , + 0x17, + 0x1A, + 0x41, + 0xAA, + 0xA4, + 0xD0, + 0x8D, + 0x12, + 0x82, + 0x1E, + 0x1E, + 3, + 0xF8, + 0x3E, + 3, + 0xC, + 0x73, + 0x80, + 0x70, + 0x44, + 0x26, + 3, + 0x24, + 0xE1, + 0x3E, + 4, + 0x4E, + 4, + 0x1C, + 0xC1, + 9, + 0xCC + //240 + , + 0x9E, + 0x90, + 0x21, + 7, + 0x90, + 0x43, + 0x64, + 0xC0, + 0xF, + 0xC6, + 0x90, + 0x9C, + 0xC1, + 0x5B, + 3, + 0xE2, + 0x1D, + 0x81, + 0xE0, + 0x5E, + 0x1D, + 3, + 0x84, + 0xB8, + 0x2C, + 0xF, + 0x80, + 0xB1, + 0x83, + 0xE0, + 0x30, + 0x41 + //260 + , + 0x1E, + 0x43, + 0x89, + 0x83, + 0x50, + 0xFC, + 0x24, + 0x2E, + 0x13, + 0x83, + 0xF1, + 0x7C, + 0x4C, + 0x2C, + 0xC9, + 0xD, + 0x83, + 0xB0, + 0xB5, + 0x82, + 0xE4, + 0xE8, + 6, + 0x9C, + 7, + 0xA0, + 0x99, + 0x1D, + 7, + 0x3E, + 0x82, + 0x8F + //280 + , + 0x70, + 0x30, + 0x74, + 0x40, + 0xCA, + 0x10, + 0xE4, + 0xE8, + 0xF, + 0x92, + 0x14, + 0x3F, + 6, + 0xF8, + 0x84, + 0x88, + 0x43, + 0x81, + 0xA, + 0x34, + 0x39, + 0x41, + 0xC6, + 0xE3, + 0x1C, + 0x47, + 3, + 0xB0, + 0xB8, + 0x13, + 0xA, + 0xC2 + //2A0 + , + 0x64, + 0xF8, + 0x18, + 0xF9, + 0x60, + 0xB3, + 0xC0, + 0x65, + 0x20, + 0x60, + 0xA6, + 0x8C, + 0xC3, + 0x81, + 0x20, + 0x30, + 0x26, + 0x1E, + 0x1C, + 0x38, + 0xD3, + 1, + 0xB0, + 0x26, + 0x40, + 0xF4, + 0xB, + 0xC3, + 0x42, + 0x1F, + 0x85, + 0x32 + //2C0 + , + 0x26, + 0x60, + 0x40, + 0xC9, + 0xCB, + 1, + 0xEC, + 0x11, + 0x28, + 0x40, + 0xFA, + 4, + 0x34, + 0xE0, + 0x70, + 0x4C, + 0x8C, + 0x1D, + 7, + 0x69, + 3, + 0x16, + 0xC8, + 4, + 0x23, + 0xE8, + 0xC6, + 0x9A, + 0xB, + 0x1A, + 3, + 0xE0 + //2E0 + , + 0x76, + 6, + 5, + 0xCF, + 0x1E, + 0xBC, + 0x58, + 0x31, + 0x71, + 0x66, + 0, + 0xF8, + 0x3F, + 4, + 0xFC, + 0xC, + 0x74, + 0x27, + 0x8A, + 0x80, + 0x71, + 0xC2, + 0x3A, + 0x26, + 6, + 0xC0, + 0x1F, + 5, + 0xF, + 0x98, + 0x40, + 0xAE + //300 + , + 1, + 0x7F, + 0xC0, + 7, + 0xFF, + 0, + 0xE, + 0xFE, + 0, + 3, + 0xDF, + 0x80, + 3, + 0xEF, + 0x80, + 0x1B, + 0xF1, + 0xC2, + 0, + 0xE7, + 0xE0, + 0x18, + 0xFC, + 0xE0, + 0x21, + 0xFC, + 0x80, + 0x3C, + 0xFC, + 0x40, + 0xE, + 0x7E + //320 + , + 0, + 0x3F, + 0x3E, + 0, + 0xF, + 0xFE, + 0, + 0x1F, + 0xFF, + 0, + 0x3E, + 0xF0, + 7, + 0xFC, + 0, + 0x7E, + 0x10, + 0x3F, + 0xFF, + 0, + 0x3F, + 0x38, + 0xE, + 0x7C, + 1, + 0x87, + 0xC, + 0xFC, + 0xC7, + 0, + 0x3E, + 4 + //340 + , + 0xF, + 0x3E, + 0x1F, + 0xF, + 0xF, + 0x1F, + 0xF, + 2, + 0x83, + 0x87, + 0xCF, + 3, + 0x87, + 0xF, + 0x3F, + 0xC0, + 7, + 0x9E, + 0x60, + 0x3F, + 0xC0, + 3, + 0xFE, + 0, + 0x3F, + 0xE0, + 0x77, + 0xE1, + 0xC0, + 0xFE, + 0xE0, + 0xC3 + //360 + , + 0xE0, + 1, + 0xDF, + 0xF8, + 3, + 7, + 0, + 0x7E, + 0x70, + 0, + 0x7C, + 0x38, + 0x18, + 0xFE, + 0xC, + 0x1E, + 0x78, + 0x1C, + 0x7C, + 0x3E, + 0xE, + 0x1F, + 0x1E, + 0x1E, + 0x3E, + 0, + 0x7F, + 0x83, + 7, + 0xDB, + 0x87, + 0x83 + //380 + , + 7, + 0xC7, + 7, + 0x10, + 0x71, + 0xFF, + 0, + 0x3F, + 0xE2, + 1, + 0xE0, + 0xC1, + 0xC3, + 0xE1, + 0, + 0x7F, + 0xC0, + 5, + 0xF0, + 0x20, + 0xF8, + 0xF0, + 0x70, + 0xFE, + 0x78, + 0x79, + 0xF8, + 2, + 0x3F, + 0xC, + 0x8F, + 3 + //3a0 + , + 0xF, + 0x9F, + 0xE0, + 0xC1, + 0xC7, + 0x87, + 3, + 0xC3, + 0xC3, + 0xB0, + 0xE1, + 0xE1, + 0xC1, + 0xE3, + 0xE0, + 0x71, + 0xF0, + 0, + 0xFC, + 0x70, + 0x7C, + 0xC, + 0x3E, + 0x38, + 0xE, + 0x1C, + 0x70, + 0xC3, + 0xC7, + 3, + 0x81, + 0xC1 + //3c0 + , + 0xC7, + 0xE7, + 0, + 0xF, + 0xC7, + 0x87, + 0x19, + 9, + 0xEF, + 0xC4, + 0x33, + 0xE0, + 0xC1, + 0xFC, + 0xF8, + 0x70, + 0xF0, + 0x78, + 0xF8, + 0xF0, + 0x61, + 0xC7, + 0, + 0x1F, + 0xF8, + 1, + 0x7C, + 0xF8, + 0xF0, + 0x78, + 0x70, + 0x3C + //3e0 + , + 0x7C, + 0xCE, + 0xE, + 0x21, + 0x83, + 0xCF, + 8, + 7, + 0x8F, + 8, + 0xC1, + 0x87, + 0x8F, + 0x80, + 0xC7, + 0xE3, + 0, + 7, + 0xF8, + 0xE0, + 0xEF, + 0, + 0x39, + 0xF7, + 0x80, + 0xE, + 0xF8, + 0xE1, + 0xE3, + 0xF8, + 0x21, + 0x9F + //400 + , + 0xC0, + 0xFF, + 3, + 0xF8, + 7, + 0xC0, + 0x1F, + 0xF8, + 0xC4, + 4, + 0xFC, + 0xC4, + 0xC1, + 0xBC, + 0x87, + 0xF0, + 0xF, + 0xC0, + 0x7F, + 5, + 0xE0, + 0x25, + 0xEC, + 0xC0, + 0x3E, + 0x84, + 0x47, + 0xF0, + 0x8E, + 3, + 0xF8, + 3 + //420 + , + 0xFB, + 0xC0, + 0x19, + 0xF8, + 7, + 0x9C, + 0xC, + 0x17, + 0xF8, + 7, + 0xE0, + 0x1F, + 0xA1, + 0xFC, + 0xF, + 0xFC, + 1, + 0xF0, + 0x3F, + 0, + 0xFE, + 3, + 0xF0, + 0x1F, + 0, + 0xFD, + 0, + 0xFF, + 0x88, + 0xD, + 0xF9, + 1 + //440 + , + 0xFF, + 0, + 0x70, + 7, + 0xC0, + 0x3E, + 0x42, + 0xF3, + 0xD, + 0xC4, + 0x7F, + 0x80, + 0xFC, + 7, + 0xF0, + 0x5E, + 0xC0, + 0x3F, + 0, + 0x78, + 0x3F, + 0x81, + 0xFF, + 1, + 0xF8, + 1, + 0xC3, + 0xE8, + 0xC, + 0xE4, + 0x64, + 0x8F + ////460 + , + 0xE4, + 0xF, + 0xF0, + 7, + 0xF0, + 0xC2, + 0x1F, + 0, + 0x7F, + 0xC0, + 0x6F, + 0x80, + 0x7E, + 3, + 0xF8, + 7, + 0xF0, + 0x3F, + 0xC0, + 0x78, + 0xF, + 0x82, + 7, + 0xFE, + 0x22, + 0x77, + 0x70, + 2, + 0x76, + 3, + 0xFE, + 0 + //480 + , + 0xFE, + 0x67, + 0, + 0x7C, + 0xC7, + 0xF1, + 0x8E, + 0xC6, + 0x3B, + 0xE0, + 0x3F, + 0x84, + 0xF3, + 0x19, + 0xD8, + 3, + 0x99, + 0xFC, + 9, + 0xB8, + 0xF, + 0xF8, + 0, + 0x9D, + 0x24, + 0x61, + 0xF9, + 0xD, + 0, + 0xFD, + 3, + 0xF0 + //4a0 + , + 0x1F, + 0x90, + 0x3F, + 1, + 0xF8, + 0x1F, + 0xD0, + 0xF, + 0xF8, + 0x37, + 1, + 0xF8, + 7, + 0xF0, + 0xF, + 0xC0, + 0x3F, + 0, + 0xFE, + 3, + 0xF8, + 0xF, + 0xC0, + 0x3F, + 0, + 0xFA, + 3, + 0xF0, + 0xF, + 0x80, + 0xFF, + 1 + //4c0 + , + 0xB8, + 7, + 0xF0, + 1, + 0xFC, + 1, + 0xBC, + 0x80, + 0x13, + 0x1E, + 0, + 0x7F, + 0xE1, + 0x40, + 0x7F, + 0xA0, + 0x7F, + 0xB0, + 0, + 0x3F, + 0xC0, + 0x1F, + 0xC0, + 0x38, + 0xF, + 0xF0, + 0x1F, + 0x80, + 0xFF, + 1, + 0xFC, + 3 + //4e0 + , + 0xF1, + 0x7E, + 1, + 0xFE, + 1, + 0xF0, + 0xFF, + 0, + 0x7F, + 0xC0, + 0x1D, + 7, + 0xF0, + 0xF, + 0xC0, + 0x7E, + 6, + 0xE0, + 7, + 0xE0, + 0xF, + 0xF8, + 6, + 0xC1, + 0xFE, + 1, + 0xFC, + 3, + 0xE0, + 0xF, + 0, + 0xFC}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Render +// +//////////////////////////////////////////////////////////////////////////////////////////// + +unsigned char pitches[256]; // tab43008 + +unsigned char frequency1[256]; +unsigned char frequency2[256]; +unsigned char frequency3[256]; + +unsigned char amplitude1[256]; +unsigned char amplitude2[256]; +unsigned char amplitude3[256]; + +unsigned char sampledConsonantFlag[256]; // tab44800 + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Sam +// +//////////////////////////////////////////////////////////////////////////////////////////// + +unsigned char stress[256]; //numbers from 0 to 8 +unsigned char phonemeLength[256]; //tab40160 +unsigned char phonemeindex[256]; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// ReciterTabs +// +//////////////////////////////////////////////////////////////////////////////////////////// + +//some flags +const unsigned char tab36376[] = { + 0, 0, 0, 0, 0, 0, 0, 0, // 0-7 + 0, 0, 0, 0, 0, 0, 0, 0, // 8-15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 2, 130, // ' ', '!' + 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 2, 2, 192, 168, 176, 172, 192, 160, 184, // '@', 'A' + 160, 192, 188, 160, 172, 168, 172, 192, 160, 160, 172, 180, 164, 192, 168, 168, + 176, 192, 188, 0, 0, 0, 2, 0, // 'X', 'Y', 'Z', '[', + 32, 32, 155, 32, 192, 185, 32, 205, 163, 76, 138, 142}; + +const unsigned char rules[] = { + ']', 'A' | 0x80, ' ', '(', 'A', '.', ')', '=', + 'E', 'H', '4', 'Y', '.', ' ' | 0x80, '(', 'A', + ')', ' ', '=', 'A', 'H' | 0x80, ' ', '(', 'A', + 'R', 'E', ')', ' ', '=', 'A', 'A', 'R' | 0x80, + ' ', '(', 'A', 'R', ')', 'O', '=', 'A', + 'X', 'R' | 0x80, '(', 'A', 'R', ')', '#', '=', + 'E', 'H', '4', 'R' | 0x80, ' ', '^', '(', 'A', + 'S', ')', '#', '=', 'E', 'Y', '4', 'S' | 0x80, + '(', 'A', ')', 'W', 'A', '=', 'A', 'X' | 0x80, + '(', 'A', 'W', ')', '=', 'A', 'O', '5' | 0x80, + ' ', ':', '(', 'A', 'N', 'Y', ')', '=', + 'E', 'H', '4', 'N', 'I', 'Y' | 0x80, '(', 'A', + ')', '^', '+', '#', '=', 'E', 'Y', '5' | 0x80, + '#', ':', '(', 'A', 'L', 'L', 'Y', ')', + '=', 'U', 'L', 'I', 'Y' | 0x80, ' ', '(', 'A', + 'L', ')', '#', '=', 'U', 'L' | 0x80, '(', 'A', + 'G', 'A', 'I', 'N', ')', '=', 'A', 'X', + 'G', 'E', 'H', '4', 'N' | 0x80, '#', ':', '(', + 'A', 'G', ')', 'E', '=', 'I', 'H', 'J' | 0x80, + '(', 'A', ')', '^', '%', '=', 'E', 'Y' | 0x80, + '(', 'A', ')', '^', '+', ':', '#', '=', + 'A', 'E' | 0x80, ' ', ':', '(', 'A', ')', '^', + '+', ' ', '=', 'E', 'Y', '4' | 0x80, ' ', '(', + 'A', 'R', 'R', ')', '=', 'A', 'X', 'R' | 0x80, + '(', 'A', 'R', 'R', ')', '=', 'A', 'E', + '4', 'R' | 0x80, ' ', '^', '(', 'A', 'R', ')', + ' ', '=', 'A', 'A', '5', 'R' | 0x80, '(', 'A', + 'R', ')', '=', 'A', 'A', '5', 'R' | 0x80, '(', + 'A', 'I', 'R', ')', '=', 'E', 'H', '4', + 'R' | 0x80, '(', 'A', 'I', ')', '=', 'E', 'Y', + '4' | 0x80, '(', 'A', 'Y', ')', '=', 'E', 'Y', + '5' | 0x80, '(', 'A', 'U', ')', '=', 'A', 'O', + '4' | 0x80, '#', ':', '(', 'A', 'L', ')', ' ', + '=', 'U', 'L' | 0x80, '#', ':', '(', 'A', 'L', + 'S', ')', ' ', '=', 'U', 'L', 'Z' | 0x80, '(', + 'A', 'L', 'K', ')', '=', 'A', 'O', '4', + 'K' | 0x80, '(', 'A', 'L', ')', '^', '=', 'A', + 'O', 'L' | 0x80, ' ', ':', '(', 'A', 'B', 'L', + 'E', ')', '=', 'E', 'Y', '4', 'B', 'U', + 'L' | 0x80, '(', 'A', 'B', 'L', 'E', ')', '=', + 'A', 'X', 'B', 'U', 'L' | 0x80, '(', 'A', ')', + 'V', 'O', '=', 'E', 'Y', '4' | 0x80, '(', 'A', + 'N', 'G', ')', '+', '=', 'E', 'Y', '4', + 'N', 'J' | 0x80, '(', 'A', 'T', 'A', 'R', 'I', + ')', '=', 'A', 'H', 'T', 'A', 'A', '4', + 'R', 'I', 'Y' | 0x80, '(', 'A', ')', 'T', 'O', + 'M', '=', 'A', 'E' | 0x80, '(', 'A', ')', 'T', + 'T', 'I', '=', 'A', 'E' | 0x80, ' ', '(', 'A', + 'T', ')', ' ', '=', 'A', 'E', 'T' | 0x80, ' ', + '(', 'A', ')', 'T', '=', 'A', 'H' | 0x80, '(', + 'A', ')', '=', 'A', 'E' | 0x80, + + ']', 'B' | 0x80, ' ', '(', 'B', ')', ' ', '=', + 'B', 'I', 'Y', '4' | 0x80, ' ', '(', 'B', 'E', + ')', '^', '#', '=', 'B', 'I', 'H' | 0x80, '(', + 'B', 'E', 'I', 'N', 'G', ')', '=', 'B', + 'I', 'Y', '4', 'I', 'H', 'N', 'X' | 0x80, ' ', + '(', 'B', 'O', 'T', 'H', ')', ' ', '=', + 'B', 'O', 'W', '4', 'T', 'H' | 0x80, ' ', '(', + 'B', 'U', 'S', ')', '#', '=', 'B', 'I', + 'H', '4', 'Z' | 0x80, '(', 'B', 'R', 'E', 'A', + 'K', ')', '=', 'B', 'R', 'E', 'Y', '5', + 'K' | 0x80, '(', 'B', 'U', 'I', 'L', ')', '=', + 'B', 'I', 'H', '4', 'L' | 0x80, '(', 'B', ')', + '=', 'B' | 0x80, + + ']', 'C' | 0x80, ' ', '(', 'C', ')', ' ', '=', + 'S', 'I', 'Y', '4' | 0x80, ' ', '(', 'C', 'H', + ')', '^', '=', 'K' | 0x80, '^', 'E', '(', 'C', + 'H', ')', '=', 'K' | 0x80, '(', 'C', 'H', 'A', + ')', 'R', '#', '=', 'K', 'E', 'H', '5' | 0x80, + '(', 'C', 'H', ')', '=', 'C', 'H' | 0x80, ' ', + 'S', '(', 'C', 'I', ')', '#', '=', 'S', + 'A', 'Y', '4' | 0x80, '(', 'C', 'I', ')', 'A', + '=', 'S', 'H' | 0x80, '(', 'C', 'I', ')', 'O', + '=', 'S', 'H' | 0x80, '(', 'C', 'I', ')', 'E', + 'N', '=', 'S', 'H' | 0x80, '(', 'C', 'I', 'T', + 'Y', ')', '=', 'S', 'I', 'H', 'T', 'I', + 'Y' | 0x80, '(', 'C', ')', '+', '=', 'S' | 0x80, '(', + 'C', 'K', ')', '=', 'K' | 0x80, '(', 'C', 'O', + 'M', 'M', 'O', 'D', 'O', 'R', 'E', ')', + '=', 'K', 'A', 'A', '4', 'M', 'A', 'H', + 'D', 'O', 'H', 'R' | 0x80, '(', 'C', 'O', 'M', + ')', '=', 'K', 'A', 'H', 'M' | 0x80, '(', 'C', + 'U', 'I', 'T', ')', '=', 'K', 'I', 'H', + 'T' | 0x80, '(', 'C', 'R', 'E', 'A', ')', '=', + 'K', 'R', 'I', 'Y', 'E', 'Y' | 0x80, '(', 'C', + ')', '=', 'K' | 0x80, + + ']', 'D' | 0x80, ' ', '(', 'D', ')', ' ', '=', + 'D', 'I', 'Y', '4' | 0x80, ' ', '(', 'D', 'R', + '.', ')', ' ', '=', 'D', 'A', 'A', '4', + 'K', 'T', 'E', 'R' | 0x80, '#', ':', '(', 'D', + 'E', 'D', ')', ' ', '=', 'D', 'I', 'H', + 'D' | 0x80, '.', 'E', '(', 'D', ')', ' ', '=', + 'D' | 0x80, '#', ':', '^', 'E', '(', 'D', ')', + ' ', '=', 'T' | 0x80, ' ', '(', 'D', 'E', ')', + '^', '#', '=', 'D', 'I', 'H' | 0x80, ' ', '(', + 'D', 'O', ')', ' ', '=', 'D', 'U', 'W' | 0x80, + ' ', '(', 'D', 'O', 'E', 'S', ')', '=', + 'D', 'A', 'H', 'Z' | 0x80, '(', 'D', 'O', 'N', + 'E', ')', ' ', '=', 'D', 'A', 'H', '5', + 'N' | 0x80, '(', 'D', 'O', 'I', 'N', 'G', ')', + '=', 'D', 'U', 'W', '4', 'I', 'H', 'N', + 'X' | 0x80, ' ', '(', 'D', 'O', 'W', ')', '=', + 'D', 'A', 'W' | 0x80, '#', '(', 'D', 'U', ')', + 'A', '=', 'J', 'U', 'W' | 0x80, '#', '(', 'D', + 'U', ')', '^', '#', '=', 'J', 'A', 'X' | 0x80, + '(', 'D', ')', '=', 'D' | 0x80, + + ']', 'E' | 0x80, ' ', '(', 'E', ')', ' ', '=', + 'I', 'Y', 'I', 'Y', '4' | 0x80, '#', ':', '(', + 'E', ')', ' ', '=' | 0x80, '\'', ':', '^', '(', + 'E', ')', ' ', '=' | 0x80, ' ', ':', '(', 'E', + ')', ' ', '=', 'I', 'Y' | 0x80, '#', '(', 'E', + 'D', ')', ' ', '=', 'D' | 0x80, '#', ':', '(', + 'E', ')', 'D', ' ', '=' | 0x80, '(', 'E', 'V', + ')', 'E', 'R', '=', 'E', 'H', '4', 'V' | 0x80, + '(', 'E', ')', '^', '%', '=', 'I', 'Y', + '4' | 0x80, '(', 'E', 'R', 'I', ')', '#', '=', + 'I', 'Y', '4', 'R', 'I', 'Y' | 0x80, '(', 'E', + 'R', 'I', ')', '=', 'E', 'H', '4', 'R', + 'I', 'H' | 0x80, '#', ':', '(', 'E', 'R', ')', + '#', '=', 'E', 'R' | 0x80, '(', 'E', 'R', 'R', + 'O', 'R', ')', '=', 'E', 'H', '4', 'R', + 'O', 'H', 'R' | 0x80, '(', 'E', 'R', 'A', 'S', + 'E', ')', '=', 'I', 'H', 'R', 'E', 'Y', + '5', 'S' | 0x80, '(', 'E', 'R', ')', '#', '=', + 'E', 'H', 'R' | 0x80, '(', 'E', 'R', ')', '=', + 'E', 'R' | 0x80, ' ', '(', 'E', 'V', 'E', 'N', + ')', '=', 'I', 'Y', 'V', 'E', 'H', 'N' | 0x80, + '#', ':', '(', 'E', ')', 'W', '=' | 0x80, '@', + '(', 'E', 'W', ')', '=', 'U', 'W' | 0x80, '(', + 'E', 'W', ')', '=', 'Y', 'U', 'W' | 0x80, '(', + 'E', ')', 'O', '=', 'I', 'Y' | 0x80, '#', ':', + '&', '(', 'E', 'S', ')', ' ', '=', 'I', + 'H', 'Z' | 0x80, '#', ':', '(', 'E', ')', 'S', + ' ', '=' | 0x80, '#', ':', '(', 'E', 'L', 'Y', + ')', ' ', '=', 'L', 'I', 'Y' | 0x80, '#', ':', + '(', 'E', 'M', 'E', 'N', 'T', ')', '=', + 'M', 'E', 'H', 'N', 'T' | 0x80, '(', 'E', 'F', + 'U', 'L', ')', '=', 'F', 'U', 'H', 'L' | 0x80, + '(', 'E', 'E', ')', '=', 'I', 'Y', '4' | 0x80, + '(', 'E', 'A', 'R', 'N', ')', '=', 'E', + 'R', '5', 'N' | 0x80, ' ', '(', 'E', 'A', 'R', + ')', '^', '=', 'E', 'R', '5' | 0x80, '(', 'E', + 'A', 'D', ')', '=', 'E', 'H', 'D' | 0x80, '#', + ':', '(', 'E', 'A', ')', ' ', '=', 'I', + 'Y', 'A', 'X' | 0x80, '(', 'E', 'A', ')', 'S', + 'U', '=', 'E', 'H', '5' | 0x80, '(', 'E', 'A', + ')', '=', 'I', 'Y', '5' | 0x80, '(', 'E', 'I', + 'G', 'H', ')', '=', 'E', 'Y', '4' | 0x80, '(', + 'E', 'I', ')', '=', 'I', 'Y', '4' | 0x80, ' ', + '(', 'E', 'Y', 'E', ')', '=', 'A', 'Y', + '4' | 0x80, '(', 'E', 'Y', ')', '=', 'I', 'Y' | 0x80, + '(', 'E', 'U', ')', '=', 'Y', 'U', 'W', + '5' | 0x80, '(', 'E', 'Q', 'U', 'A', 'L', ')', + '=', 'I', 'Y', '4', 'K', 'W', 'U', 'L' | 0x80, + '(', 'E', ')', '=', 'E', 'H' | 0x80, + + ']', 'F' | 0x80, ' ', '(', 'F', ')', ' ', '=', + 'E', 'H', '4', 'F' | 0x80, '(', 'F', 'U', 'L', + ')', '=', 'F', 'U', 'H', 'L' | 0x80, '(', 'F', + 'R', 'I', 'E', 'N', 'D', ')', '=', 'F', + 'R', 'E', 'H', '5', 'N', 'D' | 0x80, '(', 'F', + 'A', 'T', 'H', 'E', 'R', ')', '=', 'F', + 'A', 'A', '4', 'D', 'H', 'E', 'R' | 0x80, '(', + 'F', ')', 'F', '=' | 0x80, '(', 'F', ')', '=', + 'F' | 0x80, + + ']', 'G' | 0x80, ' ', '(', 'G', ')', ' ', '=', + 'J', 'I', 'Y', '4' | 0x80, '(', 'G', 'I', 'V', + ')', '=', 'G', 'I', 'H', '5', 'V' | 0x80, ' ', + '(', 'G', ')', 'I', '^', '=', 'G' | 0x80, '(', + 'G', 'E', ')', 'T', '=', 'G', 'E', 'H', + '5' | 0x80, 'S', 'U', '(', 'G', 'G', 'E', 'S', + ')', '=', 'G', 'J', 'E', 'H', '4', 'S' | 0x80, + '(', 'G', 'G', ')', '=', 'G' | 0x80, ' ', 'B', + '#', '(', 'G', ')', '=', 'G' | 0x80, '(', 'G', + ')', '+', '=', 'J' | 0x80, '(', 'G', 'R', 'E', + 'A', 'T', ')', '=', 'G', 'R', 'E', 'Y', + '4', 'T' | 0x80, '(', 'G', 'O', 'N', ')', 'E', + '=', 'G', 'A', 'O', '5', 'N' | 0x80, '#', '(', + 'G', 'H', ')', '=' | 0x80, ' ', '(', 'G', 'N', + ')', '=', 'N' | 0x80, '(', 'G', ')', '=', 'G' | 0x80, + + ']', 'H' | 0x80, ' ', '(', 'H', ')', ' ', '=', + 'E', 'Y', '4', 'C', 'H' | 0x80, ' ', '(', 'H', + 'A', 'V', ')', '=', '/', 'H', 'A', 'E', + '6', 'V' | 0x80, ' ', '(', 'H', 'E', 'R', 'E', + ')', '=', '/', 'H', 'I', 'Y', 'R' | 0x80, ' ', + '(', 'H', 'O', 'U', 'R', ')', '=', 'A', + 'W', '5', 'E', 'R' | 0x80, '(', 'H', 'O', 'W', + ')', '=', '/', 'H', 'A', 'W' | 0x80, '(', 'H', + ')', '#', '=', '/', 'H' | 0x80, '(', 'H', ')', + '=' | 0x80, + + ']', 'I' | 0x80, ' ', '(', 'I', 'N', ')', '=', + 'I', 'H', 'N' | 0x80, ' ', '(', 'I', ')', ' ', + '=', 'A', 'Y', '4' | 0x80, '(', 'I', ')', ' ', + '=', 'A', 'Y' | 0x80, '(', 'I', 'N', ')', 'D', + '=', 'A', 'Y', '5', 'N' | 0x80, 'S', 'E', 'M', + '(', 'I', ')', '=', 'I', 'Y' | 0x80, ' ', 'A', + 'N', 'T', '(', 'I', ')', '=', 'A', 'Y' | 0x80, + '(', 'I', 'E', 'R', ')', '=', 'I', 'Y', + 'E', 'R' | 0x80, '#', ':', 'R', '(', 'I', 'E', + 'D', ')', ' ', '=', 'I', 'Y', 'D' | 0x80, '(', + 'I', 'E', 'D', ')', ' ', '=', 'A', 'Y', + '5', 'D' | 0x80, '(', 'I', 'E', 'N', ')', '=', + 'I', 'Y', 'E', 'H', 'N' | 0x80, '(', 'I', 'E', + ')', 'T', '=', 'A', 'Y', '4', 'E', 'H' | 0x80, + '(', 'I', '\'', ')', '=', 'A', 'Y', '5' | 0x80, + ' ', ':', '(', 'I', ')', '^', '%', '=', + 'A', 'Y', '5' | 0x80, ' ', ':', '(', 'I', 'E', + ')', ' ', '=', 'A', 'Y', '4' | 0x80, '(', 'I', + ')', '%', '=', 'I', 'Y' | 0x80, '(', 'I', 'E', + ')', '=', 'I', 'Y', '4' | 0x80, ' ', '(', 'I', + 'D', 'E', 'A', ')', '=', 'A', 'Y', 'D', + 'I', 'Y', '5', 'A', 'H' | 0x80, '(', 'I', ')', + '^', '+', ':', '#', '=', 'I', 'H' | 0x80, '(', + 'I', 'R', ')', '#', '=', 'A', 'Y', 'R' | 0x80, + '(', 'I', 'Z', ')', '%', '=', 'A', 'Y', + 'Z' | 0x80, '(', 'I', 'S', ')', '%', '=', 'A', + 'Y', 'Z' | 0x80, 'I', '^', '(', 'I', ')', '^', + '#', '=', 'I', 'H' | 0x80, '+', '^', '(', 'I', + ')', '^', '+', '=', 'A', 'Y' | 0x80, '#', ':', + '^', '(', 'I', ')', '^', '+', '=', 'I', + 'H' | 0x80, '(', 'I', ')', '^', '+', '=', 'A', + 'Y' | 0x80, '(', 'I', 'R', ')', '=', 'E', 'R' | 0x80, + '(', 'I', 'G', 'H', ')', '=', 'A', 'Y', + '4' | 0x80, '(', 'I', 'L', 'D', ')', '=', 'A', + 'Y', '5', 'L', 'D' | 0x80, ' ', '(', 'I', 'G', + 'N', ')', '=', 'I', 'H', 'G', 'N' | 0x80, '(', + 'I', 'G', 'N', ')', ' ', '=', 'A', 'Y', + '4', 'N' | 0x80, '(', 'I', 'G', 'N', ')', '^', + '=', 'A', 'Y', '4', 'N' | 0x80, '(', 'I', 'G', + 'N', ')', '%', '=', 'A', 'Y', '4', 'N' | 0x80, + '(', 'I', 'C', 'R', 'O', ')', '=', 'A', + 'Y', '4', 'K', 'R', 'O', 'H' | 0x80, '(', 'I', + 'Q', 'U', 'E', ')', '=', 'I', 'Y', '4', + 'K' | 0x80, '(', 'I', ')', '=', 'I', 'H' | 0x80, + + ']', 'J' | 0x80, ' ', '(', 'J', ')', ' ', '=', + 'J', 'E', 'Y', '4' | 0x80, '(', 'J', ')', '=', + 'J' | 0x80, + + ']', 'K' | 0x80, ' ', '(', 'K', ')', ' ', '=', + 'K', 'E', 'Y', '4' | 0x80, ' ', '(', 'K', ')', + 'N', '=' | 0x80, '(', 'K', ')', '=', 'K' | 0x80, + + ']', 'L' | 0x80, ' ', '(', 'L', ')', ' ', '=', + 'E', 'H', '4', 'L' | 0x80, '(', 'L', 'O', ')', + 'C', '#', '=', 'L', 'O', 'W' | 0x80, 'L', '(', + 'L', ')', '=' | 0x80, '#', ':', '^', '(', 'L', + ')', '%', '=', 'U', 'L' | 0x80, '(', 'L', 'E', + 'A', 'D', ')', '=', 'L', 'I', 'Y', 'D' | 0x80, + ' ', '(', 'L', 'A', 'U', 'G', 'H', ')', + '=', 'L', 'A', 'E', '4', 'F' | 0x80, '(', 'L', + ')', '=', 'L' | 0x80, + + ']', 'M' | 0x80, ' ', '(', 'M', ')', ' ', '=', + 'E', 'H', '4', 'M' | 0x80, ' ', '(', 'M', 'R', + '.', ')', ' ', '=', 'M', 'I', 'H', '4', + 'S', 'T', 'E', 'R' | 0x80, ' ', '(', 'M', 'S', + '.', ')', '=', 'M', 'I', 'H', '5', 'Z' | 0x80, + ' ', '(', 'M', 'R', 'S', '.', ')', ' ', + '=', 'M', 'I', 'H', '4', 'S', 'I', 'X', + 'Z' | 0x80, '(', 'M', 'O', 'V', ')', '=', 'M', + 'U', 'W', '4', 'V' | 0x80, '(', 'M', 'A', 'C', + 'H', 'I', 'N', ')', '=', 'M', 'A', 'H', + 'S', 'H', 'I', 'Y', '5', 'N' | 0x80, 'M', '(', + 'M', ')', '=' | 0x80, '(', 'M', ')', '=', 'M' | 0x80, + + ']', 'N' | 0x80, ' ', '(', 'N', ')', ' ', '=', + 'E', 'H', '4', 'N' | 0x80, 'E', '(', 'N', 'G', + ')', '+', '=', 'N', 'J' | 0x80, '(', 'N', 'G', + ')', 'R', '=', 'N', 'X', 'G' | 0x80, '(', 'N', + 'G', ')', '#', '=', 'N', 'X', 'G' | 0x80, '(', + 'N', 'G', 'L', ')', '%', '=', 'N', 'X', + 'G', 'U', 'L' | 0x80, '(', 'N', 'G', ')', '=', + 'N', 'X' | 0x80, '(', 'N', 'K', ')', '=', 'N', + 'X', 'K' | 0x80, ' ', '(', 'N', 'O', 'W', ')', + ' ', '=', 'N', 'A', 'W', '4' | 0x80, 'N', '(', + 'N', ')', '=' | 0x80, '(', 'N', 'O', 'N', ')', + 'E', '=', 'N', 'A', 'H', '4', 'N' | 0x80, '(', + 'N', ')', '=', 'N' | 0x80, + + ']', 'O' | 0x80, ' ', '(', 'O', ')', ' ', '=', + 'O', 'H', '4', 'W' | 0x80, '(', 'O', 'F', ')', + ' ', '=', 'A', 'H', 'V' | 0x80, ' ', '(', 'O', + 'H', ')', ' ', '=', 'O', 'W', '5' | 0x80, '(', + 'O', 'R', 'O', 'U', 'G', 'H', ')', '=', + 'E', 'R', '4', 'O', 'W' | 0x80, '#', ':', '(', + 'O', 'R', ')', ' ', '=', 'E', 'R' | 0x80, '#', + ':', '(', 'O', 'R', 'S', ')', ' ', '=', + 'E', 'R', 'Z' | 0x80, '(', 'O', 'R', ')', '=', + 'A', 'O', 'R' | 0x80, ' ', '(', 'O', 'N', 'E', + ')', '=', 'W', 'A', 'H', 'N' | 0x80, '#', '(', + 'O', 'N', 'E', ')', ' ', '=', 'W', 'A', + 'H', 'N' | 0x80, '(', 'O', 'W', ')', '=', 'O', + 'W' | 0x80, ' ', '(', 'O', 'V', 'E', 'R', ')', + '=', 'O', 'W', '5', 'V', 'E', 'R' | 0x80, 'P', + 'R', '(', 'O', ')', 'V', '=', 'U', 'W', + '4' | 0x80, '(', 'O', 'V', ')', '=', 'A', 'H', + '4', 'V' | 0x80, '(', 'O', ')', '^', '%', '=', + 'O', 'W', '5' | 0x80, '(', 'O', ')', '^', 'E', + 'N', '=', 'O', 'W' | 0x80, '(', 'O', ')', '^', + 'I', '#', '=', 'O', 'W', '5' | 0x80, '(', 'O', + 'L', ')', 'D', '=', 'O', 'W', '4', 'L' | 0x80, + '(', 'O', 'U', 'G', 'H', 'T', ')', '=', + 'A', 'O', '5', 'T' | 0x80, '(', 'O', 'U', 'G', + 'H', ')', '=', 'A', 'H', '5', 'F' | 0x80, ' ', + '(', 'O', 'U', ')', '=', 'A', 'W' | 0x80, 'H', + '(', 'O', 'U', ')', 'S', '#', '=', 'A', + 'W', '4' | 0x80, '(', 'O', 'U', 'S', ')', '=', + 'A', 'X', 'S' | 0x80, '(', 'O', 'U', 'R', ')', + '=', 'O', 'H', 'R' | 0x80, '(', 'O', 'U', 'L', + 'D', ')', '=', 'U', 'H', '5', 'D' | 0x80, '(', + 'O', 'U', ')', '^', 'L', '=', 'A', 'H', + '5' | 0x80, '(', 'O', 'U', 'P', ')', '=', 'U', + 'W', '5', 'P' | 0x80, '(', 'O', 'U', ')', '=', + 'A', 'W' | 0x80, '(', 'O', 'Y', ')', '=', 'O', + 'Y' | 0x80, '(', 'O', 'I', 'N', 'G', ')', '=', + 'O', 'W', '4', 'I', 'H', 'N', 'X' | 0x80, '(', + 'O', 'I', ')', '=', 'O', 'Y', '5' | 0x80, '(', + 'O', 'O', 'R', ')', '=', 'O', 'H', '5', + 'R' | 0x80, '(', 'O', 'O', 'K', ')', '=', 'U', + 'H', '5', 'K' | 0x80, 'F', '(', 'O', 'O', 'D', + ')', '=', 'U', 'W', '5', 'D' | 0x80, 'L', '(', + 'O', 'O', 'D', ')', '=', 'A', 'H', '5', + 'D' | 0x80, 'M', '(', 'O', 'O', 'D', ')', '=', + 'U', 'W', '5', 'D' | 0x80, '(', 'O', 'O', 'D', + ')', '=', 'U', 'H', '5', 'D' | 0x80, 'F', '(', + 'O', 'O', 'T', ')', '=', 'U', 'H', '5', + 'T' | 0x80, '(', 'O', 'O', ')', '=', 'U', 'W', + '5' | 0x80, '(', 'O', '\'', ')', '=', 'O', 'H' | 0x80, + '(', 'O', ')', 'E', '=', 'O', 'W' | 0x80, '(', + 'O', ')', ' ', '=', 'O', 'W' | 0x80, '(', 'O', + 'A', ')', '=', 'O', 'W', '4' | 0x80, ' ', '(', + 'O', 'N', 'L', 'Y', ')', '=', 'O', 'W', + '4', 'N', 'L', 'I', 'Y' | 0x80, ' ', '(', 'O', + 'N', 'C', 'E', ')', '=', 'W', 'A', 'H', + '4', 'N', 'S' | 0x80, '(', 'O', 'N', '\'', 'T', + ')', '=', 'O', 'W', '4', 'N', 'T' | 0x80, 'C', + '(', 'O', ')', 'N', '=', 'A', 'A' | 0x80, '(', + 'O', ')', 'N', 'G', '=', 'A', 'O' | 0x80, ' ', + ':', '^', '(', 'O', ')', 'N', '=', 'A', + 'H' | 0x80, 'I', '(', 'O', 'N', ')', '=', 'U', + 'N' | 0x80, '#', ':', '(', 'O', 'N', ')', '=', + 'U', 'N' | 0x80, '#', '^', '(', 'O', 'N', ')', + '=', 'U', 'N' | 0x80, '(', 'O', ')', 'S', 'T', + '=', 'O', 'W' | 0x80, '(', 'O', 'F', ')', '^', + '=', 'A', 'O', '4', 'F' | 0x80, '(', 'O', 'T', + 'H', 'E', 'R', ')', '=', 'A', 'H', '5', + 'D', 'H', 'E', 'R' | 0x80, 'R', '(', 'O', ')', + 'B', '=', 'R', 'A', 'A' | 0x80, '^', 'R', '(', + 'O', ')', ':', '#', '=', 'O', 'W', '5' | 0x80, + '(', 'O', 'S', 'S', ')', ' ', '=', 'A', + 'O', '5', 'S' | 0x80, '#', ':', '^', '(', 'O', + 'M', ')', '=', 'A', 'H', 'M' | 0x80, '(', 'O', + ')', '=', 'A', 'A' | 0x80, + + ']', 'P' | 0x80, ' ', '(', 'P', ')', ' ', '=', + 'P', 'I', 'Y', '4' | 0x80, '(', 'P', 'H', ')', + '=', 'F' | 0x80, '(', 'P', 'E', 'O', 'P', 'L', + ')', '=', 'P', 'I', 'Y', '5', 'P', 'U', + 'L' | 0x80, '(', 'P', 'O', 'W', ')', '=', 'P', + 'A', 'W', '4' | 0x80, '(', 'P', 'U', 'T', ')', + ' ', '=', 'P', 'U', 'H', 'T' | 0x80, '(', 'P', + ')', 'P', '=' | 0x80, '(', 'P', ')', 'S', '=' | 0x80, + '(', 'P', ')', 'N', '=' | 0x80, '(', 'P', 'R', + 'O', 'F', '.', ')', '=', 'P', 'R', 'O', + 'H', 'F', 'E', 'H', '4', 'S', 'E', 'R' | 0x80, + '(', 'P', ')', '=', 'P' | 0x80, + + ']', 'Q' | 0x80, ' ', '(', 'Q', ')', ' ', '=', + 'K', 'Y', 'U', 'W', '4' | 0x80, '(', 'Q', 'U', + 'A', 'R', ')', '=', 'K', 'W', 'O', 'H', + '5', 'R' | 0x80, '(', 'Q', 'U', ')', '=', 'K', + 'W' | 0x80, '(', 'Q', ')', '=', 'K' | 0x80, ']', 'R' | 0x80, + ' ', '(', 'R', ')', ' ', '=', 'A', 'A', + '5', 'R' | 0x80, ' ', '(', 'R', 'E', ')', '^', + '#', '=', 'R', 'I', 'Y' | 0x80, '(', 'R', ')', + 'R', '=' | 0x80, '(', 'R', ')', '=', 'R' | 0x80, + + ']', 'S' | 0x80, ' ', '(', 'S', ')', ' ', '=', + 'E', 'H', '4', 'S' | 0x80, '(', 'S', 'H', ')', + '=', 'S', 'H' | 0x80, '#', '(', 'S', 'I', 'O', + 'N', ')', '=', 'Z', 'H', 'U', 'N' | 0x80, '(', + 'S', 'O', 'M', 'E', ')', '=', 'S', 'A', + 'H', 'M' | 0x80, '#', '(', 'S', 'U', 'R', ')', + '#', '=', 'Z', 'H', 'E', 'R' | 0x80, '(', 'S', + 'U', 'R', ')', '#', '=', 'S', 'H', 'E', + 'R' | 0x80, '#', '(', 'S', 'U', ')', '#', '=', + 'Z', 'H', 'U', 'W' | 0x80, '#', '(', 'S', 'S', + 'U', ')', '#', '=', 'S', 'H', 'U', 'W' | 0x80, + '#', '(', 'S', 'E', 'D', ')', '=', 'Z', + 'D' | 0x80, '#', '(', 'S', ')', '#', '=', 'Z' | 0x80, + '(', 'S', 'A', 'I', 'D', ')', '=', 'S', + 'E', 'H', 'D' | 0x80, '^', '(', 'S', 'I', 'O', + 'N', ')', '=', 'S', 'H', 'U', 'N' | 0x80, '(', + 'S', ')', 'S', '=' | 0x80, '.', '(', 'S', ')', + ' ', '=', 'Z' | 0x80, '#', ':', '.', 'E', '(', + 'S', ')', ' ', '=', 'Z' | 0x80, '#', ':', '^', + '#', '(', 'S', ')', ' ', '=', 'S' | 0x80, 'U', + '(', 'S', ')', ' ', '=', 'S' | 0x80, ' ', ':', + '#', '(', 'S', ')', ' ', '=', 'Z' | 0x80, '#', + '#', '(', 'S', ')', ' ', '=', 'Z' | 0x80, ' ', + '(', 'S', 'C', 'H', ')', '=', 'S', 'K' | 0x80, + '(', 'S', ')', 'C', '+', '=' | 0x80, '#', '(', + 'S', 'M', ')', '=', 'Z', 'U', 'M' | 0x80, '#', + '(', 'S', 'N', ')', '\'', '=', 'Z', 'U', + 'M' | 0x80, '(', 'S', 'T', 'L', 'E', ')', '=', + 'S', 'U', 'L' | 0x80, '(', 'S', ')', '=', 'S' | 0x80, + + ']', 'T' | 0x80, ' ', '(', 'T', ')', ' ', '=', + 'T', 'I', 'Y', '4' | 0x80, ' ', '(', 'T', 'H', + 'E', ')', ' ', '#', '=', 'D', 'H', 'I', + 'Y' | 0x80, ' ', '(', 'T', 'H', 'E', ')', ' ', + '=', 'D', 'H', 'A', 'X' | 0x80, '(', 'T', 'O', + ')', ' ', '=', 'T', 'U', 'X' | 0x80, ' ', '(', + 'T', 'H', 'A', 'T', ')', '=', 'D', 'H', + 'A', 'E', 'T' | 0x80, ' ', '(', 'T', 'H', 'I', + 'S', ')', ' ', '=', 'D', 'H', 'I', 'H', + 'S' | 0x80, ' ', '(', 'T', 'H', 'E', 'Y', ')', + '=', 'D', 'H', 'E', 'Y' | 0x80, ' ', '(', 'T', + 'H', 'E', 'R', 'E', ')', '=', 'D', 'H', + 'E', 'H', 'R' | 0x80, '(', 'T', 'H', 'E', 'R', + ')', '=', 'D', 'H', 'E', 'R' | 0x80, '(', 'T', + 'H', 'E', 'I', 'R', ')', '=', 'D', 'H', + 'E', 'H', 'R' | 0x80, ' ', '(', 'T', 'H', 'A', + 'N', ')', ' ', '=', 'D', 'H', 'A', 'E', + 'N' | 0x80, ' ', '(', 'T', 'H', 'E', 'M', ')', + ' ', '=', 'D', 'H', 'A', 'E', 'N' | 0x80, '(', + 'T', 'H', 'E', 'S', 'E', ')', ' ', '=', + 'D', 'H', 'I', 'Y', 'Z' | 0x80, ' ', '(', 'T', + 'H', 'E', 'N', ')', '=', 'D', 'H', 'E', + 'H', 'N' | 0x80, '(', 'T', 'H', 'R', 'O', 'U', + 'G', 'H', ')', '=', 'T', 'H', 'R', 'U', + 'W', '4' | 0x80, '(', 'T', 'H', 'O', 'S', 'E', + ')', '=', 'D', 'H', 'O', 'H', 'Z' | 0x80, '(', + 'T', 'H', 'O', 'U', 'G', 'H', ')', ' ', + '=', 'D', 'H', 'O', 'W' | 0x80, '(', 'T', 'O', + 'D', 'A', 'Y', ')', '=', 'T', 'U', 'X', + 'D', 'E', 'Y' | 0x80, '(', 'T', 'O', 'M', 'O', + ')', 'R', 'R', 'O', 'W', '=', 'T', 'U', + 'M', 'A', 'A', '5' | 0x80, '(', 'T', 'O', ')', + 'T', 'A', 'L', '=', 'T', 'O', 'W', '5' | 0x80, + ' ', '(', 'T', 'H', 'U', 'S', ')', '=', + 'D', 'H', 'A', 'H', '4', 'S' | 0x80, '(', 'T', + 'H', ')', '=', 'T', 'H' | 0x80, '#', ':', '(', + 'T', 'E', 'D', ')', '=', 'T', 'I', 'X', + 'D' | 0x80, 'S', '(', 'T', 'I', ')', '#', 'N', + '=', 'C', 'H' | 0x80, '(', 'T', 'I', ')', 'O', + '=', 'S', 'H' | 0x80, '(', 'T', 'I', ')', 'A', + '=', 'S', 'H' | 0x80, '(', 'T', 'I', 'E', 'N', + ')', '=', 'S', 'H', 'U', 'N' | 0x80, '(', 'T', + 'U', 'R', ')', '#', '=', 'C', 'H', 'E', + 'R' | 0x80, '(', 'T', 'U', ')', 'A', '=', 'C', + 'H', 'U', 'W' | 0x80, ' ', '(', 'T', 'W', 'O', + ')', '=', 'T', 'U', 'W' | 0x80, '&', '(', 'T', + ')', 'E', 'N', ' ', '=' | 0x80, '(', 'T', ')', + '=', 'T' | 0x80, + + ']', 'U' | 0x80, ' ', '(', 'U', ')', ' ', '=', + 'Y', 'U', 'W', '4' | 0x80, ' ', '(', 'U', 'N', + ')', 'I', '=', 'Y', 'U', 'W', 'N' | 0x80, ' ', + '(', 'U', 'N', ')', '=', 'A', 'H', 'N' | 0x80, + ' ', '(', 'U', 'P', 'O', 'N', ')', '=', + 'A', 'X', 'P', 'A', 'O', 'N' | 0x80, '@', '(', + 'U', 'R', ')', '#', '=', 'U', 'H', '4', + 'R' | 0x80, '(', 'U', 'R', ')', '#', '=', 'Y', + 'U', 'H', '4', 'R' | 0x80, '(', 'U', 'R', ')', + '=', 'E', 'R' | 0x80, '(', 'U', ')', '^', ' ', + '=', 'A', 'H' | 0x80, '(', 'U', ')', '^', '^', + '=', 'A', 'H', '5' | 0x80, '(', 'U', 'Y', ')', + '=', 'A', 'Y', '5' | 0x80, ' ', 'G', '(', 'U', + ')', '#', '=' | 0x80, 'G', '(', 'U', ')', '%', + '=' | 0x80, 'G', '(', 'U', ')', '#', '=', 'W' | 0x80, + '#', 'N', '(', 'U', ')', '=', 'Y', 'U', + 'W' | 0x80, '@', '(', 'U', ')', '=', 'U', 'W' | 0x80, + '(', 'U', ')', '=', 'Y', 'U', 'W' | 0x80, + + ']', 'V' | 0x80, ' ', '(', 'V', ')', ' ', '=', + 'V', 'I', 'Y', '4' | 0x80, '(', 'V', 'I', 'E', + 'W', ')', '=', 'V', 'Y', 'U', 'W', '5' | 0x80, + '(', 'V', ')', '=', 'V' | 0x80, + + ']', 'W' | 0x80, ' ', '(', 'W', ')', ' ', '=', + 'D', 'A', 'H', '4', 'B', 'U', 'L', 'Y', + 'U', 'W' | 0x80, ' ', '(', 'W', 'E', 'R', 'E', + ')', '=', 'W', 'E', 'R' | 0x80, '(', 'W', 'A', + ')', 'S', 'H', '=', 'W', 'A', 'A' | 0x80, '(', + 'W', 'A', ')', 'S', 'T', '=', 'W', 'E', + 'Y' | 0x80, '(', 'W', 'A', ')', 'S', '=', 'W', + 'A', 'H' | 0x80, '(', 'W', 'A', ')', 'T', '=', + 'W', 'A', 'A' | 0x80, '(', 'W', 'H', 'E', 'R', + 'E', ')', '=', 'W', 'H', 'E', 'H', 'R' | 0x80, + '(', 'W', 'H', 'A', 'T', ')', '=', 'W', + 'H', 'A', 'H', 'T' | 0x80, '(', 'W', 'H', 'O', + 'L', ')', '=', '/', 'H', 'O', 'W', 'L' | 0x80, + '(', 'W', 'H', 'O', ')', '=', '/', 'H', + 'U', 'W' | 0x80, '(', 'W', 'H', ')', '=', 'W', + 'H' | 0x80, '(', 'W', 'A', 'R', ')', '#', '=', + 'W', 'E', 'H', 'R' | 0x80, '(', 'W', 'A', 'R', + ')', '=', 'W', 'A', 'O', 'R' | 0x80, '(', 'W', + 'O', 'R', ')', '^', '=', 'W', 'E', 'R' | 0x80, + '(', 'W', 'R', ')', '=', 'R' | 0x80, '(', 'W', + 'O', 'M', ')', 'A', '=', 'W', 'U', 'H', + 'M' | 0x80, '(', 'W', 'O', 'M', ')', 'E', '=', + 'W', 'I', 'H', 'M' | 0x80, '(', 'W', 'E', 'A', + ')', 'R', '=', 'W', 'E', 'H' | 0x80, '(', 'W', + 'A', 'N', 'T', ')', '=', 'W', 'A', 'A', + '5', 'N', 'T' | 0x80, 'A', 'N', 'S', '(', 'W', + 'E', 'R', ')', '=', 'E', 'R' | 0x80, '(', 'W', + ')', '=', 'W' | 0x80, + + ']', 'X' | 0x80, ' ', '(', 'X', ')', ' ', '=', + 'E', 'H', '4', 'K', 'R' | 0x80, ' ', '(', 'X', + ')', '=', 'Z' | 0x80, '(', 'X', ')', '=', 'K', + 'S' | 0x80, + + ']', 'Y' | 0x80, ' ', '(', 'Y', ')', ' ', '=', + 'W', 'A', 'Y', '4' | 0x80, '(', 'Y', 'O', 'U', + 'N', 'G', ')', '=', 'Y', 'A', 'H', 'N', + 'X' | 0x80, ' ', '(', 'Y', 'O', 'U', 'R', ')', + '=', 'Y', 'O', 'H', 'R' | 0x80, ' ', '(', 'Y', + 'O', 'U', ')', '=', 'Y', 'U', 'W' | 0x80, ' ', + '(', 'Y', 'E', 'S', ')', '=', 'Y', 'E', + 'H', 'S' | 0x80, ' ', '(', 'Y', ')', '=', 'Y' | 0x80, + 'F', '(', 'Y', ')', '=', 'A', 'Y' | 0x80, 'P', + 'S', '(', 'Y', 'C', 'H', ')', '=', 'A', + 'Y', 'K' | 0x80, '#', ':', '^', '(', 'Y', ')', + '=', 'I', 'Y' | 0x80, '#', ':', '^', '(', 'Y', + ')', 'I', '=', 'I', 'Y' | 0x80, ' ', ':', '(', + 'Y', ')', ' ', '=', 'A', 'Y' | 0x80, ' ', ':', + '(', 'Y', ')', '#', '=', 'A', 'Y' | 0x80, ' ', + ':', '(', 'Y', ')', '^', '+', ':', '#', + '=', 'I', 'H' | 0x80, ' ', ':', '(', 'Y', ')', + '^', '#', '=', 'A', 'Y' | 0x80, '(', 'Y', ')', + '=', 'I', 'H' | 0x80, + + ']', 'Z' | 0x80, ' ', '(', 'Z', ')', ' ', '=', + 'Z', 'I', 'Y', '4' | 0x80, '(', 'Z', ')', '=', + 'Z' | 0x80, 'j' | 0x80}; + +const unsigned char rules2[] = { + '(', 'A', ')', '=' | 0x80, '(', '!', ')', '=', + '.' | 0x80, '(', '"', ')', ' ', '=', '-', 'A', + 'H', '5', 'N', 'K', 'W', 'O', 'W', 'T', + '-' | 0x80, '(', '"', ')', '=', 'K', 'W', 'O', + 'W', '4', 'T', '-' | 0x80, '(', '#', ')', '=', + ' ', 'N', 'A', 'H', '4', 'M', 'B', 'E', + 'R' | 0x80, '(', '$', ')', '=', ' ', 'D', 'A', + 'A', '4', 'L', 'E', 'R' | 0x80, '(', '%', ')', + '=', ' ', 'P', 'E', 'R', 'S', 'E', 'H', + '4', 'N', 'T' | 0x80, '(', '&', ')', '=', ' ', + 'A', 'E', 'N', 'D' | 0x80, '(', '\'', ')', '=' | 0x80, + '(', '*', ')', '=', ' ', 'A', 'E', '4', + 'S', 'T', 'E', 'R', 'I', 'H', 'S', 'K' | 0x80, + '(', '+', ')', '=', ' ', 'P', 'L', 'A', + 'H', '4', 'S' | 0x80, '(', ',', ')', '=', ',' | 0x80, + ' ', '(', '-', ')', ' ', '=', '-' | 0x80, '(', + '-', ')', '=' | 0x80, '(', '.', ')', '=', ' ', + 'P', 'O', 'Y', 'N', 'T' | 0x80, '(', '/', ')', + '=', ' ', 'S', 'L', 'A', 'E', '4', 'S', + 'H' | 0x80, '(', '0', ')', '=', ' ', 'Z', 'I', + 'Y', '4', 'R', 'O', 'W' | 0x80, ' ', '(', '1', + 'S', 'T', ')', '=', 'F', 'E', 'R', '4', + 'S', 'T' | 0x80, ' ', '(', '1', '0', 'T', 'H', + ')', '=', 'T', 'E', 'H', '4', 'N', 'T', + 'H' | 0x80, '(', '1', ')', '=', ' ', 'W', 'A', + 'H', '4', 'N' | 0x80, ' ', '(', '2', 'N', 'D', + ')', '=', 'S', 'E', 'H', '4', 'K', 'U', + 'N', 'D' | 0x80, '(', '2', ')', '=', ' ', 'T', + 'U', 'W', '4' | 0x80, ' ', '(', '3', 'R', 'D', + ')', '=', 'T', 'H', 'E', 'R', '4', 'D' | 0x80, + '(', '3', ')', '=', ' ', 'T', 'H', 'R', + 'I', 'Y', '4' | 0x80, '(', '4', ')', '=', ' ', + 'F', 'O', 'H', '4', 'R' | 0x80, ' ', '(', '5', + 'T', 'H', ')', '=', 'F', 'I', 'H', '4', + 'F', 'T', 'H' | 0x80, '(', '5', ')', '=', ' ', + 'F', 'A', 'Y', '4', 'V' | 0x80, ' ', '(', '6', + '4', ')', ' ', '=', 'S', 'I', 'H', '4', + 'K', 'S', 'T', 'I', 'Y', ' ', 'F', 'O', + 'H', 'R' | 0x80, '(', '6', ')', '=', ' ', 'S', + 'I', 'H', '4', 'K', 'S' | 0x80, '(', '7', ')', + '=', ' ', 'S', 'E', 'H', '4', 'V', 'U', + 'N' | 0x80, ' ', '(', '8', 'T', 'H', ')', '=', + 'E', 'Y', '4', 'T', 'H' | 0x80, '(', '8', ')', + '=', ' ', 'E', 'Y', '4', 'T' | 0x80, '(', '9', + ')', '=', ' ', 'N', 'A', 'Y', '4', 'N' | 0x80, + '(', ':', ')', '=', '.' | 0x80, '(', ';', ')', + '=', '.' | 0x80, '(', '<', ')', '=', ' ', 'L', + 'E', 'H', '4', 'S', ' ', 'D', 'H', 'A', + 'E', 'N' | 0x80, '(', '=', ')', '=', ' ', 'I', + 'Y', '4', 'K', 'W', 'U', 'L', 'Z' | 0x80, '(', + '>', ')', '=', ' ', 'G', 'R', 'E', 'Y', + '4', 'T', 'E', 'R', ' ', 'D', 'H', 'A', + 'E', 'N' | 0x80, '(', '?', ')', '=', '?' | 0x80, '(', + '@', ')', '=', ' ', 'A', 'E', '6', 'T' | 0x80, + '(', '^', ')', '=', ' ', 'K', 'A', 'E', + '4', 'R', 'I', 'X', 'T' | 0x80, ']', 'A' | 0x80}; + +//26 items. From 'A' to 'Z' +// positions for mem62 and mem63 for each character +const unsigned char tab37489[] = {0, 149, 247, 162, 57, 197, 6, 126, 199, 38, 55, 78, 145, + 241, 85, 161, 254, 36, 69, 45, 167, 54, 83, 46, 71, 218}; + +const unsigned char tab37515[] = {125, 126, 126, 127, 128, 129, 130, 130, 130, 132, 132, 132, 132, + 132, 133, 135, 135, 136, 136, 137, 138, 139, 139, 140, 140, 140}; + +void STM32SAM::Output8BitAry(int index, unsigned char ary[5]) { + int k; + + uint32_t bufferposOld = bufferpos; + + bufferpos += timetable[oldtimetableindex][index]; + oldtimetableindex = index; + + int sample_uS = bufferpos - bufferposOld; + + uint32_t f = 0; + + // write a little bit in advance + for(k = 0; k < 5; k++) { + // buffer[bufferpos / 50 + k] = ary[k]; + + // f = micros() + sample_uS / (_STM32SAM_SPEED + 1); + // while(micros() < f) { + // }; + f = sample_uS / (_STM32SAM_SPEED + 1); + furi_delay_us(f); + SetAUDIO(ary[k]); + // delayMicroseconds(sample_uS / 5 ); + } + + // SetAUDIO(ary[0]); +} + +void STM32SAM::Output8Bit(int index, unsigned char A) { + unsigned char ary[5] = {A, A, A, A, A}; + Output8BitAry(index, ary); +} + +//written by me because of different table positions. +// mem[47] = ... +// 168=pitches +// 169=frequency1 +// 170=frequency2 +// 171=frequency3 +// 172=amplitude1 +// 173=amplitude2 +// 174=amplitude3 +unsigned char STM32SAM::Read(unsigned char p, unsigned char Y) { + switch(p) { + case 168: + return pitches[Y]; + case 169: + return frequency1[Y]; + case 170: + return frequency2[Y]; + case 171: + return frequency3[Y]; + case 172: + return amplitude1[Y]; + case 173: + return amplitude2[Y]; + case 174: + return amplitude3[Y]; + } + // Serial1.println("Error reading to tables"); + return 0; +} + +void STM32SAM::Write(unsigned char p, unsigned char Y, unsigned char value) { + switch(p) { + case 168: + pitches[Y] = value; + return; + case 169: + frequency1[Y] = value; + return; + case 170: + frequency2[Y] = value; + return; + case 171: + frequency3[Y] = value; + return; + case 172: + amplitude1[Y] = value; + return; + case 173: + amplitude2[Y] = value; + return; + case 174: + amplitude3[Y] = value; + return; + } + //Serial1.println("Error writing to tables\n"); +} + +// ------------------------------------------------------------------------- +//Code48227 +// Render a sampled sound from the sampleTable. +// +// Phoneme Sample Start Sample End +// 32: S* 15 255 +// 33: SH 257 511 +// 34: F* 559 767 +// 35: TH 583 767 +// 36: /H 903 1023 +// 37: /X 1135 1279 +// 38: Z* 84 119 +// 39: ZH 340 375 +// 40: V* 596 639 +// 41: DH 596 631 +// +// 42: CH +// 43: ** 399 511 +// +// 44: J* +// 45: ** 257 276 +// 46: ** +// +// 66: P* +// 67: ** 743 767 +// 68: ** +// +// 69: T* +// 70: ** 231 255 +// 71: ** +// +// The SampledPhonemesTable[] holds flags indicating if a phoneme is +// voiced or not. If the upper 5 bits are zero, the sample is voiced. +// +// Samples in the sampleTable are compressed, with bits being converted to +// bytes from high bit to low, as follows: +// +// unvoiced 0 bit -> X +// unvoiced 1 bit -> 5 +// +// voiced 0 bit -> 6 +// voiced 1 bit -> 24 +// +// Where X is a value from the table: +// +// { 0x18, 0x1A, 0x17, 0x17, 0x17 }; +// +// The index into this table is determined by masking off the lower +// 3 bits from the SampledPhonemesTable: +// +// index = (SampledPhonemesTable[i] & 7) - 1; +// +// For voices samples, samples are interleaved between voiced output. + +// Code48227() +void STM32SAM::RenderSample(unsigned char* mem66) { + int tempA; + // current phoneme's index + mem49 = Y; + + // mask low three bits and subtract 1 get value to + // convert 0 bits on unvoiced samples. + A = mem39 & 7; + X = A - 1; + + // store the result + mem56 = X; + + // determine which offset to use from table { 0x18, 0x1A, 0x17, 0x17, 0x17 } + // T, S, Z 0 0x18 + // CH, J, SH, ZH 1 0x1A + // P, F*, V, TH, DH 2 0x17 + // /H 3 0x17 + // /X 4 0x17 + + // get value from the table + mem53 = tab48426[X]; + mem47 = X; //46016+mem[56]*256 + + // voiced sample? + A = mem39 & 248; + if(A == 0) { + // voiced phoneme: Z*, ZH, V*, DH + Y = mem49; + A = pitches[mem49] >> 4; + + // jump to voiced portion + goto pos48315; + } + + Y = A ^ 255; +pos48274: + + // step through the 8 bits in the sample + mem56 = 8; + + // get the next sample from the table + // mem47*256 = offset to start of samples + A = sampleTable[mem47 * 256 + Y]; +pos48280: + + // left shift to get the high bit + tempA = A; + A = A << 1; + //48281: BCC 48290 + + // bit not set? + if((tempA & 128) == 0) { + // convert the bit to value from table + X = mem53; + //mem[54296] = X; + // output the byte + Output8Bit(1, (X & 0x0f) * 16); + // if X != 0, exit loop + if(X != 0) goto pos48296; + } + + // output a 5 for the on bit + Output8Bit(2, 5 * 16); + + //48295: NOP +pos48296: + + X = 0; + + // decrement counter + mem56--; + + // if not done, jump to top of loop + if(mem56 != 0) goto pos48280; + + // increment position + Y++; + if(Y != 0) goto pos48274; + + // restore values and return + mem44 = 1; + Y = mem49; + return; + + unsigned char phase1; + +pos48315: + // handle voiced samples here + + // number of samples? + phase1 = A ^ 255; + + Y = *mem66; + do { + //pos48321: + + // shift through all 8 bits + mem56 = 8; + //A = Read(mem47, Y); + + // fetch value from table + A = sampleTable[mem47 * 256 + Y]; + + // loop 8 times + //pos48327: + do { + //48327: ASL A + //48328: BCC 48337 + + // left shift and check high bit + tempA = A; + A = A << 1; + if((tempA & 128) != 0) { + // if bit set, output 26 + X = 26; + Output8Bit(3, (X & 0xf) * 16); + } else { + //timetable 4 + // bit is not set, output a 6 + X = 6; + Output8Bit(4, (X & 0xf) * 16); + } + + mem56--; + } while(mem56 != 0); + + // move ahead in the table + Y++; + + // continue until counter done + phase1++; + + } while(phase1 != 0); + // if (phase1 != 0) goto pos48321; + + // restore values and return + A = 1; + mem44 = 1; + *mem66 = Y; + Y = mem49; + return; +} + +// RENDER THE PHONEMES IN THE LIST +// +// The phoneme list is converted into sound through the steps: +// +// 1. Copy each phoneme number of times into the frames list, +// where each frame represents 10 milliseconds of sound. +// +// 2. Determine the transitions lengths between phonemes, and linearly +// interpolate the values across the frames. +// +// 3. Offset the pitches by the fundamental frequency. +// +// 4. Render the each frame. + +//void Code47574() +void STM32SAM::Render() { + unsigned char phase1 = 0; //mem43 + unsigned char phase2 = 0; + unsigned char phase3 = 0; + unsigned char mem66 = 0; + unsigned char mem38 = 0; + unsigned char mem40 = 0; + unsigned char speedcounter = 0; //mem45 + unsigned char mem48 = 0; + int i; + if(phonemeIndexOutput[0] == 255) return; //exit if no data + + A = 0; + X = 0; + mem44 = 0; + + // CREATE FRAMES + // + // The length parameter in the list corresponds to the number of frames + // to expand the phoneme to. Each frame represents 10 milliseconds of time. + // So a phoneme with a length of 7 = 7 frames = 70 milliseconds duration. + // + // The parameters are copied from the phoneme to the frame verbatim. + + // pos47587: + do { + // get the index + Y = mem44; + // get the phoneme at the index + A = phonemeIndexOutput[mem44]; + mem56 = A; + + // if terminal phoneme, exit the loop + if(A == 255) break; + + // period phoneme *. + if(A == 1) { + // add rising inflection + A = 1; + mem48 = 1; + //goto pos48376; + AddInflection(mem48, phase1); + } + /* + if (A == 2) goto pos48372; + */ + + // question mark phoneme? + if(A == 2) { + // create falling inflection + mem48 = 255; + AddInflection(mem48, phase1); + } + // pos47615: + + // get the stress amount (more stress = higher pitch) + phase1 = tab47492[stressOutput[Y] + 1]; + + // get number of frames to write + phase2 = phonemeLengthOutput[Y]; + Y = mem56; + + // copy from the source to the frames list + do { + frequency1[X] = freq1data[Y]; // F1 frequency + frequency2[X] = freq2data[Y]; // F2 frequency + frequency3[X] = freq3data[Y]; // F3 frequency + amplitude1[X] = ampl1data[Y]; // F1 amplitude + amplitude2[X] = ampl2data[Y]; // F2 amplitude + amplitude3[X] = ampl3data[Y]; // F3 amplitude + sampledConsonantFlag[X] = + sampledConsonantFlags[Y]; // phoneme data for sampled consonants + pitches[X] = pitch + phase1; // pitch + X++; + phase2--; + } while(phase2 != 0); + mem44++; + } while(mem44 != 0); + // ------------------- + //pos47694: + + // CREATE TRANSITIONS + // + // Linear transitions are now created to smoothly connect the + // end of one sustained portion of a phoneme to the following + // phoneme. + // + // To do this, three tables are used: + // + // Table Purpose + // ========= ================================================== + // blendRank Determines which phoneme's blend values are used. + // + // blendOut The number of frames at the end of the phoneme that + // will be used to transition to the following phoneme. + // + // blendIn The number of frames of the following phoneme that + // will be used to transition into that phoneme. + // + // In creating a transition between two phonemes, the phoneme + // with the HIGHEST rank is used. Phonemes are ranked on how much + // their identity is based on their transitions. For example, + // vowels are and diphthongs are identified by their sustained portion, + // rather than the transitions, so they are given low values. In contrast, + // stop consonants (P, B, T, K) and glides (Y, L) are almost entirely + // defined by their transitions, and are given high rank values. + // + // Here are the rankings used by SAM: + // + // Rank Type Phonemes + // 2 All vowels IY, IH, etc. + // 5 Diphthong endings YX, WX, ER + // 8 Terminal liquid consonants LX, WX, YX, N, NX + // 9 Liquid consonants L, RX, W + // 10 Glide R, OH + // 11 Glide WH + // 18 Voiceless fricatives S, SH, F, TH + // 20 Voiced fricatives Z, ZH, V, DH + // 23 Plosives, stop consonants P, T, K, KX, DX, CH + // 26 Stop consonants J, GX, B, D, G + // 27-29 Stop consonants (internal) ** + // 30 Unvoiced consonants /H, /X and Q* + // 160 Nasal M + // + // To determine how many frames to use, the two phonemes are + // compared using the blendRank[] table. The phoneme with the + // higher rank is selected. In case of a tie, a blend of each is used: + // + // if blendRank[phoneme1] == blendRank[phomneme2] + // // use lengths from each phoneme + // outBlendFrames = outBlend[phoneme1] + // inBlendFrames = outBlend[phoneme2] + // else if blendRank[phoneme1] > blendRank[phoneme2] + // // use lengths from first phoneme + // outBlendFrames = outBlendLength[phoneme1] + // inBlendFrames = inBlendLength[phoneme1] + // else + // // use lengths from the second phoneme + // // note that in and out are SWAPPED! + // outBlendFrames = inBlendLength[phoneme2] + // inBlendFrames = outBlendLength[phoneme2] + // + // Blend lengths can't be less than zero. + // + // Transitions are assumed to be symetrical, so if the transition + // values for the second phoneme are used, the inBlendLength and + // outBlendLength values are SWAPPED. + // + // For most of the parameters, SAM interpolates over the range of the last + // outBlendFrames-1 and the first inBlendFrames. + // + // The exception to this is the Pitch[] parameter, which is interpolates the + // pitch from the CENTER of the current phoneme to the CENTER of the next + // phoneme. + // + // Here are two examples. First, For example, consider the word "SUN" (S AH N) + // + // Phoneme Duration BlendWeight OutBlendFrames InBlendFrames + // S 2 18 1 3 + // AH 8 2 4 4 + // N 7 8 1 2 + // + // The formant transitions for the output frames are calculated as follows: + // + // flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch + // ------------------------------------------------ + // S + // 241 0 6 0 73 0 99 61 Use S (weight 18) for transition instead of AH (weight 2) + // 241 0 6 0 73 0 99 61 <-- (OutBlendFrames-1) = (1-1) = 0 frames + // AH + // 0 2 10 2 66 0 96 59 * <-- InBlendFrames = 3 frames + // 0 4 14 3 59 0 93 57 * + // 0 8 18 5 52 0 90 55 * + // 0 15 22 9 44 1 87 53 + // 0 15 22 9 44 1 87 53 + // 0 15 22 9 44 1 87 53 Use N (weight 8) for transition instead of AH (weight 2). + // 0 15 22 9 44 1 87 53 Since N is second phoneme, reverse the IN and OUT values. + // 0 11 17 8 47 1 98 56 * <-- (InBlendFrames-1) = (2-1) = 1 frames + // N + // 0 8 12 6 50 1 109 58 * <-- OutBlendFrames = 1 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // + // Now, consider the reverse "NUS" (N AH S): + // + // flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch + // ------------------------------------------------ + // N + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 + // 0 5 6 5 54 0 121 61 Use N (weight 8) for transition instead of AH (weight 2) + // 0 5 6 5 54 0 121 61 <-- (OutBlendFrames-1) = (1-1) = 0 frames + // AH + // 0 8 11 6 51 0 110 59 * <-- InBlendFrames = 2 + // 0 11 16 8 48 0 99 56 * + // 0 15 22 9 44 1 87 53 Use S (weight 18) for transition instead of AH (weight 2) + // 0 15 22 9 44 1 87 53 Since S is second phoneme, reverse the IN and OUT values. + // 0 9 18 5 51 1 90 55 * <-- (InBlendFrames-1) = (3-1) = 2 + // 0 4 14 3 58 1 93 57 * + // S + // 241 2 10 2 65 1 96 59 * <-- OutBlendFrames = 1 + // 241 0 6 0 73 0 99 61 + + A = 0; + mem44 = 0; + mem49 = 0; // mem49 starts at as 0 + X = 0; + while(1) //while No. 1 + { + // get the current and following phoneme + Y = phonemeIndexOutput[X]; + A = phonemeIndexOutput[X + 1]; + X++; + + // exit loop at end token + if(A == 255) break; //goto pos47970; + + // get the ranking of each phoneme + X = A; + mem56 = blendRank[A]; + A = blendRank[Y]; + + // compare the rank - lower rank value is stronger + if(A == mem56) { + // same rank, so use out blend lengths from each phoneme + phase1 = outBlendLength[Y]; + phase2 = outBlendLength[X]; + } else if(A < mem56) { + // first phoneme is stronger, so us it's blend lengths + phase1 = inBlendLength[X]; + phase2 = outBlendLength[X]; + } else { + // second phoneme is stronger, so use it's blend lengths + // note the out/in are swapped + phase1 = outBlendLength[Y]; + phase2 = inBlendLength[Y]; + } + + Y = mem44; + A = mem49 + phonemeLengthOutput[mem44]; // A is mem49 + length + mem49 = A; // mem49 now holds length + position + A = A + phase2; //Maybe Problem because of carry flag + + //47776: ADC 42 + speedcounter = A; + mem47 = 168; + phase3 = mem49 - phase1; // what is mem49 + A = phase1 + phase2; // total transition? + mem38 = A; + + X = A; + X -= 2; + if((X & 128) == 0) + do //while No. 2 + { + //pos47810: + + // mem47 is used to index the tables: + // 168 pitches[] + // 169 frequency1 + // 170 frequency2 + // 171 frequency3 + // 172 amplitude1 + // 173 amplitude2 + // 174 amplitude3 + + mem40 = mem38; + + if(mem47 == 168) // pitch + { + // unlike the other values, the pitches[] interpolates from + // the middle of the current phoneme to the middle of the + // next phoneme + + unsigned char mem36, mem37; + // half the width of the current phoneme + mem36 = phonemeLengthOutput[mem44] >> 1; + // half the width of the next phoneme + mem37 = phonemeLengthOutput[mem44 + 1] >> 1; + // sum the values + mem40 = mem36 + mem37; // length of both halves + mem37 += mem49; // center of next phoneme + mem36 = mem49 - mem36; // center index of current phoneme + A = Read( + mem47, mem37); // value at center of next phoneme - end interpolation value + //A = mem[address]; + + Y = mem36; // start index of interpolation + mem53 = A - Read(mem47, mem36); // value to center of current phoneme + } else { + // value to interpolate to + A = Read(mem47, speedcounter); + // position to start interpolation from + Y = phase3; + // value to interpolate from + mem53 = A - Read(mem47, phase3); + } + + //Code47503(mem40); + // ML : Code47503 is division with remainder, and mem50 gets the sign + + // calculate change per frame + signed char m53 = (signed char)mem53; + mem50 = mem53 & 128; + unsigned char m53abs = abs(m53); + mem51 = m53abs % mem40; //abs((char)m53) % mem40; + mem53 = (unsigned char)((signed char)(m53) / mem40); + + // interpolation range + X = mem40; // number of frames to interpolate over + Y = phase3; // starting frame + + // linearly interpolate values + + mem56 = 0; + //47907: CLC + //pos47908: + while(1) //while No. 3 + { + A = Read(mem47, Y) + mem53; //carry alway cleared + + mem48 = A; + Y++; + X--; + if(X == 0) break; + + mem56 += mem51; + if(mem56 >= mem40) //??? + { + mem56 -= mem40; //carry? is set + //if ((mem56 & 128)==0) + if((mem50 & 128) == 0) { + //47935: BIT 50 + //47937: BMI 47943 + if(mem48 != 0) mem48++; + } else + mem48--; + } + //pos47945: + Write(mem47, Y, mem48); + } //while No. 3 + + //pos47952: + mem47++; + //if (mem47 != 175) goto pos47810; + } while(mem47 != 175); //while No. 2 + //pos47963: + mem44++; + X = mem44; + } //while No. 1 + + //goto pos47701; + //pos47970: + + // add the length of this phoneme + mem48 = mem49 + phonemeLengthOutput[mem44]; + + // ASSIGN PITCH CONTOUR + // + // This subtracts the F1 frequency from the pitch to create a + // pitch contour. Without this, the output would be at a single + // pitch level (monotone). + + // don't adjust pitch if in sing mode + if(!singmode) { + // iterate through the buffer + for(i = 0; i < 256; i++) { + // subtract half the frequency of the formant 1. + // this adds variety to the voice + pitches[i] -= (frequency1[i] >> 1); + } + } + + phase1 = 0; + phase2 = 0; + phase3 = 0; + mem49 = 0; + speedcounter = 72; //sam standard speed + + // RESCALE AMPLITUDE + // + // Rescale volume from a linear scale to decibels. + // + + //amplitude rescaling + for(i = 255; i >= 0; i--) { + amplitude1[i] = amplitudeRescale[amplitude1[i]]; + amplitude2[i] = amplitudeRescale[amplitude2[i]]; + amplitude3[i] = amplitudeRescale[amplitude3[i]]; + } + + Y = 0; + A = pitches[0]; + mem44 = A; + X = A; + mem38 = A - (A >> 2); // 3/4*A ??? + + // PROCESS THE FRAMES + // + // In traditional vocal synthesis, the glottal pulse drives filters, which + // are attenuated to the frequencies of the formants. + // + // SAM generates these formants directly with sin and rectangular waves. + // To simulate them being driven by the glottal pulse, the waveforms are + // reset at the beginning of each glottal pulse. + + //finally the loop for sound output + //pos48078: + while(1) { + // get the sampled information on the phoneme + A = sampledConsonantFlag[Y]; + mem39 = A; + + // unvoiced sampled phoneme? + A = A & 248; + if(A != 0) { + // render the sample for the phoneme + RenderSample(&mem66); + + // skip ahead two in the phoneme buffer + Y += 2; + mem48 -= 2; + } else { + // simulate the glottal pulse and formants + unsigned char ary[5]; + unsigned int p1 = + phase1 * 256; // Fixed point integers because we need to divide later on + unsigned int p2 = phase2 * 256; + unsigned int p3 = phase3 * 256; + int k; + for(k = 0; k < 5; k++) { + signed char sp1 = (signed char)sinus[0xff & (p1 >> 8)]; + signed char sp2 = (signed char)sinus[0xff & (p2 >> 8)]; + signed char rp3 = (signed char)rectangle[0xff & (p3 >> 8)]; + signed int sin1 = sp1 * ((unsigned char)amplitude1[Y] & 0x0f); + signed int sin2 = sp2 * ((unsigned char)amplitude2[Y] & 0x0f); + signed int rect = rp3 * ((unsigned char)amplitude3[Y] & 0x0f); + signed int mux = sin1 + sin2 + rect; + mux /= 32; + mux += 128; // Go from signed to unsigned amplitude + ary[k] = mux; + p1 += frequency1[Y] * 256 / 4; // Compromise, this becomes a shift and works well + p2 += frequency2[Y] * 256 / 4; + p3 += frequency3[Y] * 256 / 4; + } + // output the accumulated value + Output8BitAry(0, ary); + speedcounter--; + if(speedcounter != 0) goto pos48155; + Y++; //go to next amplitude + + // decrement the frame count + mem48--; + } + + // if the frame count is zero, exit the loop + if(mem48 == 0) return; + speedcounter = speed; + pos48155: + + // decrement the remaining length of the glottal pulse + mem44--; + + // finished with a glottal pulse? + if(mem44 == 0) { + pos48159: + // fetch the next glottal pulse length + A = pitches[Y]; + mem44 = A; + A = A - (A >> 2); + mem38 = A; + + // reset the formant wave generators to keep them in + // sync with the glottal pulse + phase1 = 0; + phase2 = 0; + phase3 = 0; + continue; + } + + // decrement the count + mem38--; + + // is the count non-zero and the sampled flag is zero? + if((mem38 != 0) || (mem39 == 0)) { + // reset the phase of the formants to match the pulse + phase1 += frequency1[Y]; + phase2 += frequency2[Y]; + phase3 += frequency3[Y]; + continue; + } + + // voiced sampled phonemes interleave the sample with the + // glottal pulse. The sample flag is non-zero, so render + // the sample for the phoneme. + RenderSample(&mem66); + goto pos48159; + } //while + + // The following code is never reached. It's left over from when + // the voiced sample code was part of this loop, instead of part + // of RenderSample(); + + //pos48315: + int tempA; + phase1 = A ^ 255; + Y = mem66; + do { + //pos48321: + + mem56 = 8; + A = Read(mem47, Y); + + //pos48327: + do { + //48327: ASL A + //48328: BCC 48337 + tempA = A; + A = A << 1; + if((tempA & 128) != 0) { + X = 26; + // mem[54296] = X; + bufferpos += 150; + // + // + // buffer[bufferpos / 50] = (X & 15) * 16; + // + // + + } else { + //mem[54296] = 6; + X = 6; + bufferpos += 150; + // + // buffer[bufferpos / 50] = (X & 15) * 16; + // + // + } + + for(X = wait2; X > 0; X--) + ; //wait + mem56--; + } while(mem56 != 0); + + Y++; + phase1++; + + } while(phase1 != 0); + // if (phase1 != 0) goto pos48321; + A = 1; + mem44 = 1; + mem66 = Y; + Y = mem49; + return; +} + +// Create a rising or falling inflection 30 frames prior to +// index X. A rising inflection is used for questions, and +// a falling inflection is used for statements. + +void STM32SAM::AddInflection(unsigned char mem48, unsigned char phase1) { + //pos48372: + // mem48 = 255; + //pos48376: + + // store the location of the punctuation + mem49 = X; + A = X; + int Atemp = A; + + // backup 30 frames + A = A - 30; + // if index is before buffer, point to start of buffer + if(Atemp <= 30) A = 0; + X = A; + + // FIXME: Explain this fix better, it's not obvious + // ML : A =, fixes a problem with invalid pitch with '.' + while((A = pitches[X]) == 127) X++; + +pos48398: + //48398: CLC + //48399: ADC 48 + + // add the inflection direction + A += mem48; + phase1 = A; + + // set the inflection + pitches[X] = A; +pos48406: + + // increment the position + X++; + + // exit if the punctuation has been reached + if(X == mem49) return; //goto pos47615; + if(pitches[X] == 255) goto pos48406; + A = phase1; + goto pos48398; +} + +/* + SAM's voice can be altered by changing the frequencies of the + mouth formant (F1) and the throat formant (F2). Only the voiced + phonemes (5-29 and 48-53) are altered. +*/ +void STM32SAM::SetMouthThroat() { + unsigned char initialFrequency; + unsigned char newFrequency = 0; + //unsigned char mouth; //mem38880 + //unsigned char throat; //mem38881 + + // mouth formants (F1) 5..29 + unsigned char mouthFormants5_29[30] = {0, 0, 0, 0, 0, 10, 14, 19, 24, 27, + 23, 21, 16, 20, 14, 18, 14, 18, 18, 16, + 13, 15, 11, 18, 14, 11, 9, 6, 6, 6}; + + // throat formants (F2) 5..29 + unsigned char throatFormants5_29[30] = {255, 255, 255, 255, 255, 84, 73, 67, 63, 40, + 44, 31, 37, 45, 73, 49, 36, 30, 51, 37, + 29, 69, 24, 50, 30, 24, 83, 46, 54, 86}; + + // there must be no zeros in this 2 tables + // formant 1 frequencies (mouth) 48..53 + unsigned char mouthFormants48_53[6] = {19, 27, 21, 27, 18, 13}; + + // formant 2 frequencies (throat) 48..53 + unsigned char throatFormants48_53[6] = {72, 39, 31, 43, 30, 34}; + + unsigned char pos = 5; //mem39216 + //pos38942: + // recalculate formant frequencies 5..29 for the mouth (F1) and throat (F2) + while(pos != 30) { + // recalculate mouth frequency + initialFrequency = mouthFormants5_29[pos]; + if(initialFrequency != 0) newFrequency = trans(mouth, initialFrequency); + freq1data[pos] = newFrequency; + + // recalculate throat frequency + initialFrequency = throatFormants5_29[pos]; + if(initialFrequency != 0) newFrequency = trans(throat, initialFrequency); + freq2data[pos] = newFrequency; + pos++; + } + + //pos39059: + // recalculate formant frequencies 48..53 + pos = 48; + Y = 0; + while(pos != 54) { + // recalculate F1 (mouth formant) + initialFrequency = mouthFormants48_53[Y]; + newFrequency = trans(mouth, initialFrequency); + freq1data[pos] = newFrequency; + + // recalculate F2 (throat formant) + initialFrequency = throatFormants48_53[Y]; + newFrequency = trans(throat, initialFrequency); + freq2data[pos] = newFrequency; + Y++; + pos++; + } +} + +//return = (mem39212*mem39213) >> 1 +unsigned char STM32SAM::trans(unsigned char mem39212, unsigned char mem39213) { + //pos39008: + unsigned char carry; + int temp; + unsigned char mem39214, mem39215; + A = 0; + mem39215 = 0; + mem39214 = 0; + X = 8; + do { + carry = mem39212 & 1; + mem39212 = mem39212 >> 1; + if(carry != 0) { + /* + 39018: LSR 39212 + 39021: BCC 39033 + */ + carry = 0; + A = mem39215; + temp = (int)A + (int)mem39213; + A = A + mem39213; + if(temp > 255) carry = 1; + mem39215 = A; + } + temp = mem39215 & 1; + mem39215 = (mem39215 >> 1) | (carry ? 128 : 0); + carry = temp; + //39033: ROR 39215 + X--; + } while(X != 0); + temp = mem39214 & 128; + mem39214 = (mem39214 << 1) | (carry ? 1 : 0); + carry = temp; + temp = mem39215 & 128; + mem39215 = (mem39215 << 1) | (carry ? 1 : 0); + carry = temp; + + return mem39215; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Sam +// +//////////////////////////////////////////////////////////////////////////////////////////// + +//char input[]={"/HAALAOAO MAYN NAAMAEAE IHSTT SAEBAASTTIHAAN \x9b\x9b\0"}; +//unsigned char input[]={"/HAALAOAO \x9b\0"}; +//unsigned char input[]={"AA \x9b\0"}; +//unsigned char input[] = {"GUH5DEHN TAEG\x9b\0"}; + +//unsigned char input[]={"AY5 AEM EY TAO4LXKIHNX KAX4MPYUX4TAH. GOW4 AH/HEH3D PAHNK.MEYK MAY8 DEY.\x9b\0"}; +//unsigned char input[]={"/HEH3LOW2, /HAW AH YUX2 TUXDEY. AY /HOH3P YUX AH FIYLIHNX OW4 KEY.\x9b\0"}; +//unsigned char input[]={"/HEY2, DHIHS IH3Z GREY2T. /HAH /HAH /HAH.AYL BIY5 BAEK.\x9b\0"}; +//unsigned char input[]={"/HAH /HAH /HAH \x9b\0"}; +//unsigned char input[]={"/HAH /HAH /HAH.\x9b\0"}; +//unsigned char input[]={".TUW BIY5Y3,, OHR NAA3T - TUW BIY5IYIY., DHAE4T IHZ DHAH KWEH4SCHAHN.\x9b\0"}; +//unsigned char input[]={"/HEY2, DHIHS \x9b\0"}; + +//unsigned char input[]={" IYIHEHAEAAAHAOOHUHUXERAXIX \x9b\0"}; +//unsigned char input[]={" RLWWYMNNXBDGJZZHVDH \x9b\0"}; +//unsigned char input[]={" SSHFTHPTKCH/H \x9b\0"}; + +//unsigned char input[]={" EYAYOYAWOWUW ULUMUNQ YXWXRXLX/XDX\x9b\0"}; + +void STM32SAM::SetInput(char* _input) { + int i, l; + l = strlen(_input); + if(l > 254) l = 254; + for(i = 0; i < l; i++) { + input[i] = _input[i]; + } + input[l] = 0; +} + +// 168=pitches +// 169=frequency1 +// 170=frequency2 +// 171=frequency3 +// 172=amplitude1 +// 173=amplitude2 +// 174=amplitude3 + +void STM32SAM::Init() { + bufferpos = 0; + int i; + SetMouthThroat(); + + bufferpos = 0; + // TODO, check for free the memory, 10 seconds of output should be more than enough + //buffer = malloc(22050*10); + + // buffer = (char*) calloc(1, sizeof(char)); + + /* + freq2data = &mem[45136]; + freq1data = &mem[45056]; + freq3data = &mem[45216]; + */ + //pitches = &mem[43008]; + /* + frequency1 = &mem[43264]; + frequency2 = &mem[43520]; + frequency3 = &mem[43776]; + */ + /* + amplitude1 = &mem[44032]; + amplitude2 = &mem[44288]; + amplitude3 = &mem[44544]; + */ + //phoneme = &mem[39904]; + /* + ampl1data = &mem[45296]; + ampl2data = &mem[45376]; + ampl3data = &mem[45456]; + */ + + for(i = 0; i < 256; i++) { + stress[i] = 0; + phonemeLength[i] = 0; + } + + for(i = 0; i < 60; i++) { + phonemeIndexOutput[i] = 0; + stressOutput[i] = 0; + phonemeLengthOutput[i] = 0; + } + phonemeindex[255] = + 255; //to prevent buffer overflow // ML : changed from 32 to 255 to stop freezing with long inputs +} + +//int Code39771() +int STM32SAM::SAMMain() { + Init(); + phonemeindex[255] = 32; //to prevent buffer overflow + + if(!Parser1()) { + return 0; + } + + Parser2(); + CopyStress(); + SetPhonemeLength(); + AdjustLengths(); + Code41240(); + do { + A = phonemeindex[X]; + if(A > 80) { + phonemeindex[X] = 255; + break; // error: delete all behind it + } + X++; + } while(X != 0); + + //pos39848: + InsertBreath(); + + //mem[40158] = 255; + + PrepareOutput(); + + return 1; +} + +//void Code48547() +void STM32SAM::PrepareOutput() { + A = 0; + X = 0; + Y = 0; + + //pos48551: + while(1) { + A = phonemeindex[X]; + if(A == 255) { + A = 255; + phonemeIndexOutput[Y] = 255; + Render(); + return; + } + if(A == 254) { + X++; + int temp = X; + //mem[48546] = X; + phonemeIndexOutput[Y] = 255; + Render(); + //X = mem[48546]; + X = temp; + Y = 0; + continue; + } + + if(A == 0) { + X++; + continue; + } + + phonemeIndexOutput[Y] = A; + phonemeLengthOutput[Y] = phonemeLength[X]; + stressOutput[Y] = stress[X]; + X++; + Y++; + } +} + +//void Code41014() +void STM32SAM::Insert( + unsigned char position /*var57*/, + unsigned char mem60, + unsigned char mem59, + unsigned char mem58) { + int i; + for(i = 253; i >= position; i--) // ML : always keep last safe-guarding 255 + { + phonemeindex[i + 1] = phonemeindex[i]; + phonemeLength[i + 1] = phonemeLength[i]; + stress[i + 1] = stress[i]; + } + + phonemeindex[position] = mem60; + phonemeLength[position] = mem59; + stress[position] = mem58; + return; +} + +//void Code48431() +void STM32SAM::InsertBreath() { + unsigned char mem54; + unsigned char mem55; + unsigned char index; //variable Y + mem54 = 255; + X++; + mem55 = 0; + unsigned char mem66 = 0; + while(1) { + //pos48440: + X = mem66; + index = phonemeindex[X]; + if(index == 255) return; + mem55 += phonemeLength[X]; + + if(mem55 < 232) { + if(index != 254) // ML : Prevents an index out of bounds problem + { + A = flags2[index] & 1; + if(A != 0) { + X++; + mem55 = 0; + Insert(X, 254, mem59, 0); + mem66++; + mem66++; + continue; + } + } + if(index == 0) mem54 = X; + mem66++; + continue; + } + X = mem54; + phonemeindex[X] = 31; // 'Q*' glottal stop + phonemeLength[X] = 4; + stress[X] = 0; + X++; + mem55 = 0; + Insert(X, 254, mem59, 0); + X++; + mem66 = X; + } +} + +// Iterates through the phoneme buffer, copying the stress value from +// the following phoneme under the following circumstance: + +// 1. The current phoneme is voiced, excluding plosives and fricatives +// 2. The following phoneme is voiced, excluding plosives and fricatives, and +// 3. The following phoneme is stressed +// +// In those cases, the stress value+1 from the following phoneme is copied. +// +// For example, the word LOITER is represented as LOY5TER, with as stress +// of 5 on the diphtong OY. This routine will copy the stress value of 6 (5+1) +// to the L that precedes it. + +//void Code41883() +void STM32SAM::CopyStress() { + // loop thought all the phonemes to be output + unsigned char pos = 0; //mem66 + while(1) { + // get the phomene + Y = phonemeindex[pos]; + + // exit at end of buffer + if(Y == 255) return; + + // if CONSONANT_FLAG set, skip - only vowels get stress + if((flags[Y] & 64) == 0) { + pos++; + continue; + } + // get the next phoneme + Y = phonemeindex[pos + 1]; + if(Y == 255) //prevent buffer overflow + { + pos++; + continue; + } else + // if the following phoneme is a vowel, skip + if((flags[Y] & 128) == 0) { + pos++; + continue; + } + + // get the stress value at the next position + Y = stress[pos + 1]; + + // if next phoneme is not stressed, skip + if(Y == 0) { + pos++; + continue; + } + + // if next phoneme is not a VOWEL OR ER, skip + if((Y & 128) != 0) { + pos++; + continue; + } + + // copy stress from prior phoneme to this one + stress[pos] = Y + 1; + + // advance pointer + pos++; + } +} + +// The input[] buffer contains a string of phonemes and stress markers along +// the lines of: +// +// DHAX KAET IHZ AH5GLIY. <0x9B> +// +// The byte 0x9B marks the end of the buffer. Some phonemes are 2 bytes +// long, such as "DH" and "AX". Others are 1 byte long, such as "T" and "Z". +// There are also stress markers, such as "5" and ".". +// +// The first character of the phonemes are stored in the table signInputTable1[]. +// The second character of the phonemes are stored in the table signInputTable2[]. +// The stress characters are arranged in low to high stress order in stressInputTable[]. +// +// The following process is used to parse the input[] buffer: +// +// Repeat until the <0x9B> character is reached: +// +// First, a search is made for a 2 character match for phonemes that do not +// end with the '*' (wildcard) character. On a match, the index of the phoneme +// is added to phonemeIndex[] and the buffer position is advanced 2 bytes. +// +// If this fails, a search is made for a 1 character match against all +// phoneme names ending with a '*' (wildcard). If this succeeds, the +// phoneme is added to phonemeIndex[] and the buffer position is advanced +// 1 byte. +// +// If this fails, search for a 1 character match in the stressInputTable[]. +// If this succeeds, the stress value is placed in the last stress[] table +// at the same index of the last added phoneme, and the buffer position is +// advanced by 1 byte. +// +// If this fails, return a 0. +// +// On success: +// +// 1. phonemeIndex[] will contain the index of all the phonemes. +// 2. The last index in phonemeIndex[] will be 255. +// 3. stress[] will contain the stress value for each phoneme + +// input[] holds the string of phonemes, each two bytes wide +// signInputTable1[] holds the first character of each phoneme +// signInputTable2[] holds te second character of each phoneme +// phonemeIndex[] holds the indexes of the phonemes after parsing input[] +// +// The parser scans through the input[], finding the names of the phonemes +// by searching signInputTable1[] and signInputTable2[]. On a match, it +// copies the index of the phoneme into the phonemeIndexTable[]. +// +// The character <0x9B> marks the end of text in input[]. When it is reached, +// the index 255 is placed at the end of the phonemeIndexTable[], and the +// function returns with a 1 indicating success. +int STM32SAM::Parser1() { + int i; + unsigned char sign1; + unsigned char sign2; + unsigned char position = 0; + X = 0; + A = 0; + Y = 0; + + // CLEAR THE STRESS TABLE + for(i = 0; i < 256; i++) stress[i] = 0; + + // THIS CODE MATCHES THE PHONEME LETTERS TO THE TABLE + // pos41078: + while(1) { + // GET THE FIRST CHARACTER FROM THE PHONEME BUFFER + sign1 = input[X]; + // TEST FOR 155 (�) END OF LINE MARKER + if(sign1 == 155) { + // MARK ENDPOINT AND RETURN + phonemeindex[position] = 255; //mark endpoint + // REACHED END OF PHONEMES, SO EXIT + return 1; //all ok + } + + // GET THE NEXT CHARACTER FROM THE BUFFER + X++; + sign2 = input[X]; + + // NOW sign1 = FIRST CHARACTER OF PHONEME, AND sign2 = SECOND CHARACTER OF PHONEME + + // TRY TO MATCH PHONEMES ON TWO TWO-CHARACTER NAME + // IGNORE PHONEMES IN TABLE ENDING WITH WILDCARDS + + // SET INDEX TO 0 + Y = 0; + pos41095: + + // GET FIRST CHARACTER AT POSITION Y IN signInputTable + // --> should change name to PhonemeNameTable1 + A = signInputTable1[Y]; + + // FIRST CHARACTER MATCHES? + if(A == sign1) { + // GET THE CHARACTER FROM THE PhonemeSecondLetterTable + A = signInputTable2[Y]; + // NOT A SPECIAL AND MATCHES SECOND CHARACTER? + if((A != '*') && (A == sign2)) { + // STORE THE INDEX OF THE PHONEME INTO THE phomeneIndexTable + phonemeindex[position] = Y; + + // ADVANCE THE POINTER TO THE phonemeIndexTable + position++; + // ADVANCE THE POINTER TO THE phonemeInputBuffer + X++; + + // CONTINUE PARSING + continue; + } + } + + // NO MATCH, TRY TO MATCH ON FIRST CHARACTER TO WILDCARD NAMES (ENDING WITH '*') + + // ADVANCE TO THE NEXT POSITION + Y++; + // IF NOT END OF TABLE, CONTINUE + if(Y != 81) goto pos41095; + + // REACHED END OF TABLE WITHOUT AN EXACT (2 CHARACTER) MATCH. + // THIS TIME, SEARCH FOR A 1 CHARACTER MATCH AGAINST THE WILDCARDS + + // RESET THE INDEX TO POINT TO THE START OF THE PHONEME NAME TABLE + Y = 0; + pos41134: + // DOES THE PHONEME IN THE TABLE END WITH '*'? + if(signInputTable2[Y] == '*') { + // DOES THE FIRST CHARACTER MATCH THE FIRST LETTER OF THE PHONEME + if(signInputTable1[Y] == sign1) { + // SAVE THE POSITION AND MOVE AHEAD + phonemeindex[position] = Y; + + // ADVANCE THE POINTER + position++; + + // CONTINUE THROUGH THE LOOP + continue; + } + } + Y++; + if(Y != 81) goto pos41134; //81 is size of PHONEME NAME table + + // FAILED TO MATCH WITH A WILDCARD. ASSUME THIS IS A STRESS + // CHARACTER. SEARCH THROUGH THE STRESS TABLE + + // SET INDEX TO POSITION 8 (END OF STRESS TABLE) + Y = 8; + + // WALK BACK THROUGH TABLE LOOKING FOR A MATCH + while((sign1 != stressInputTable[Y]) && (Y > 0)) { + // DECREMENT INDEX + Y--; + } + + // REACHED THE END OF THE SEARCH WITHOUT BREAKING OUT OF LOOP? + if(Y == 0) { + //mem[39444] = X; + //41181: JSR 42043 //Error + // FAILED TO MATCH ANYTHING, RETURN 0 ON FAILURE + return 0; + } + // SET THE STRESS FOR THE PRIOR PHONEME + stress[position - 1] = Y; + } //while +} + +//change phonemelength depedendent on stress +//void Code41203() +void STM32SAM::SetPhonemeLength() { + unsigned char A; + int position = 0; + while(phonemeindex[position] != 255) { + A = stress[position]; + //41218: BMI 41229 + if((A == 0) || ((A & 128) != 0)) { + phonemeLength[position] = phonemeLengthTable[phonemeindex[position]]; + } else { + phonemeLength[position] = phonemeStressedLengthTable[phonemeindex[position]]; + } + position++; + } +} + +void STM32SAM::Code41240() { + unsigned char pos = 0; + + while(phonemeindex[pos] != 255) { + unsigned char index; //register AC + X = pos; + index = phonemeindex[pos]; + if((flags[index] & 2) == 0) { + pos++; + continue; + } else if((flags[index] & 1) == 0) { + Insert(pos + 1, index + 1, phonemeLengthTable[index + 1], stress[pos]); + Insert(pos + 2, index + 2, phonemeLengthTable[index + 2], stress[pos]); + pos += 3; + continue; + } + + do { + X++; + A = phonemeindex[X]; + } while(A == 0); + + if(A != 255) { + if((flags[A] & 8) != 0) { + pos++; + continue; + } + if((A == 36) || (A == 37)) { + pos++; // '/H' '/X' + continue; + } + } + + Insert(pos + 1, index + 1, phonemeLengthTable[index + 1], stress[pos]); + Insert(pos + 2, index + 2, phonemeLengthTable[index + 2], stress[pos]); + pos += 3; + }; +} + +// Rewrites the phonemes using the following rules: +// +// -> WX +// -> YX +// UL -> AX L +// UM -> AX M +// -> Q +// T R -> CH R +// D R -> J R +// R -> RX +// L -> LX +// G S -> G Z +// K -> KX +// G -> GX +// S P -> S B +// S T -> S D +// S K -> S G +// S KX -> S GX +// UW -> UX +// CH -> CH CH' (CH requires two phonemes to represent it) +// J -> J J' (J requires two phonemes to represent it) +// T -> DX +// D -> DX + +//void Code41397() +void STM32SAM::Parser2() { + unsigned char pos = 0; //mem66; + unsigned char mem58 = 0; + + // Loop through phonemes + while(1) { + // SET X TO THE CURRENT POSITION + X = pos; + // GET THE PHONEME AT THE CURRENT POSITION + A = phonemeindex[pos]; + + // Is phoneme pause? + if(A == 0) { + // Move ahead to the + pos++; + continue; + } + + // If end of phonemes flag reached, exit routine + if(A == 255) return; + + // Copy the current phoneme index to Y + Y = A; + + // RULE: + // -> WX + // -> YX + // Example: OIL, COW + + // Check for DIPHTONG + if((flags[A] & 16) == 0) goto pos41457; + + // Not a diphthong. Get the stress + mem58 = stress[pos]; + + // End in IY sound? + A = flags[Y] & 32; + + // If ends with IY, use YX, else use WX + if(A == 0) + A = 20; + else + A = 21; // 'WX' = 20 'YX' = 21 + //pos41443: + // Insert at WX or YX following, copying the stress + + Insert(pos + 1, A, mem59, mem58); + X = pos; + // Jump to ??? + goto pos41749; + + pos41457: + + // RULE: + // UL -> AX L + // Example: MEDDLE + + // Get phoneme + A = phonemeindex[X]; + // Skip this rule if phoneme is not UL + if(A != 78) goto pos41487; // 'UL' + A = 24; // 'L' //change 'UL' to 'AX L' + + pos41466: + // Get current phoneme stress + mem58 = stress[X]; + + // Change UL to AX + phonemeindex[X] = 13; // 'AX' + // Perform insert. Note code below may jump up here with different values + Insert(X + 1, A, mem59, mem58); + pos++; + // Move to next phoneme + continue; + + pos41487: + + // RULE: + // UM -> AX M + // Example: ASTRONOMY + + // Skip rule if phoneme != UM + if(A != 79) goto pos41495; // 'UM' + // Jump up to branch - replaces current phoneme with AX and continues + A = 27; // 'M' //change 'UM' to 'AX M' + + goto pos41466; + pos41495: + + // RULE: + // UN -> AX N + // Example: FUNCTION + + // Skip rule if phoneme != UN + if(A != 80) goto pos41503; // 'UN' + + // Jump up to branch - replaces current phoneme with AX and continues + A = 28; // 'N' //change UN to 'AX N' + + goto pos41466; + pos41503: + + // RULE: + // -> Q + // EXAMPLE: AWAY EIGHT + + Y = A; + // VOWEL set? + A = flags[A] & 128; + + // Skip if not a vowel + if(A != 0) { + // Get the stress + A = stress[X]; + + // If stressed... + if(A != 0) { + // Get the following phoneme + X++; + A = phonemeindex[X]; + // If following phoneme is a pause + + if(A == 0) { + // Get the phoneme following pause + X++; + Y = phonemeindex[X]; + + // Check for end of buffer flag + if(Y == 255) //buffer overflow + // ??? Not sure about these flags + A = 65 & 128; + else + // And VOWEL flag to current phoneme's flags + A = flags[Y] & 128; + + // If following phonemes is not a pause + if(A != 0) { + // If the following phoneme is not stressed + A = stress[X]; + if(A != 0) { + // 31 = 'Q' + Insert(X, 31, mem59, 0); + pos++; + continue; + } + } + } + } + } + + // RULES FOR PHONEMES BEFORE R + // T R -> CH R + // Example: TRACK + + // Get current position and phoneme + X = pos; + A = phonemeindex[pos]; + if(A != 23) goto pos41611; // 'R' + + // Look at prior phoneme + X--; + A = phonemeindex[pos - 1]; + //pos41567: + if(A == 69) // 'T' + { + phonemeindex[pos - 1] = 42; + goto pos41779; + } + + // RULES FOR PHONEMES BEFORE R + // D R -> J R + // Example: DRY + + // Prior phonemes D? + if(A == 57) // 'D' + { + // Change D to J + phonemeindex[pos - 1] = 44; + + goto pos41788; + } + + // RULES FOR PHONEMES BEFORE R + // R -> RX + // Example: ART + + // If vowel flag is set change R to RX + A = flags[A] & 128; + + if(A != 0) phonemeindex[pos] = 18; // 'RX' + + // continue to next phoneme + pos++; + continue; + + pos41611: + + // RULE: + // L -> LX + // Example: ALL + + // Is phoneme L? + if(A == 24) // 'L' + { + // If prior phoneme does not have VOWEL flag set, move to next phoneme + if((flags[phonemeindex[pos - 1]] & 128) == 0) { + pos++; + continue; + } + // Prior phoneme has VOWEL flag set, so change L to LX and move to next phoneme + + phonemeindex[X] = 19; // 'LX' + pos++; + continue; + } + + // RULE: + // G S -> G Z + // + // Can't get to fire - + // 1. The G -> GX rule intervenes + // 2. Reciter already replaces GS -> GZ + + // Is current phoneme S? + if(A == 32) // 'S' + { + // If prior phoneme is not G, move to next phoneme + if(phonemeindex[pos - 1] != 60) { + pos++; + continue; + } + // Replace S with Z and move on + + phonemeindex[pos] = 38; // 'Z' + pos++; + continue; + } + + // RULE: + // K -> KX + // Example: COW + + // Is current phoneme K? + if(A == 72) // 'K' + { + // Get next phoneme + Y = phonemeindex[pos + 1]; + // If at end, replace current phoneme with KX + if(Y == 255) + phonemeindex[pos] = 75; // ML : prevents an index out of bounds problem + else { + // VOWELS AND DIPHTONGS ENDING WITH IY SOUND flag set? + A = flags[Y] & 32; + + // Replace with KX + if(A == 0) phonemeindex[pos] = 75; // 'KX' + } + } else + + // RULE: + // G -> GX + // Example: GO + + // Is character a G? + if(A == 60) // 'G' + { + // Get the following character + unsigned char index = phonemeindex[pos + 1]; + + // At end of buffer? + if(index == 255) //prevent buffer overflow + { + pos++; + continue; + } else + // If diphtong ending with YX, move continue processing next phoneme + if((flags[index] & 32) != 0) { + pos++; + continue; + } + // replace G with GX and continue processing next phoneme + + phonemeindex[pos] = 63; // 'GX' + pos++; + continue; + } + + // RULE: + // S P -> S B + // S T -> S D + // S K -> S G + // S KX -> S GX + // Examples: SPY, STY, SKY, SCOWL + + Y = phonemeindex[pos]; + //pos41719: + // Replace with softer version? + A = flags[Y] & 1; + if(A == 0) goto pos41749; + A = phonemeindex[pos - 1]; + if(A != 32) // 'S' + { + A = Y; + goto pos41812; + } + // Replace with softer version + + phonemeindex[pos] = Y - 12; + pos++; + continue; + + pos41749: + + // RULE: + // UW -> UX + // + // Example: NEW, DEW, SUE, ZOO, THOO, TOO + + // UW -> UX + + A = phonemeindex[X]; + if(A == 53) // 'UW' + { + // ALVEOLAR flag set? + Y = phonemeindex[X - 1]; + A = flags2[Y] & 4; + // If not set, continue processing next phoneme + if(A == 0) { + pos++; + continue; + } + + phonemeindex[X] = 16; + pos++; + continue; + } + pos41779: + + // RULE: + // CH -> CH CH' (CH requires two phonemes to represent it) + // Example: CHEW + + if(A == 42) // 'CH' + { + // pos41783: + + Insert(X + 1, A + 1, mem59, stress[X]); + pos++; + continue; + } + + pos41788: + + // RULE: + // J -> J J' (J requires two phonemes to represent it) + // Example: JAY + + if(A == 44) // 'J' + { + Insert(X + 1, A + 1, mem59, stress[X]); + pos++; + continue; + } + + // Jump here to continue + pos41812: + + // RULE: Soften T following vowel + // NOTE: This rule fails for cases such as "ODD" + // T -> DX + // D -> DX + // Example: PARTY, TARDY + + // Past this point, only process if phoneme is T or D + + if(A != 69) // 'T' + if(A != 57) { + pos++; // 'D' + continue; + } + //pos41825: + + // If prior phoneme is not a vowel, continue processing phonemes + if((flags[phonemeindex[X - 1]] & 128) == 0) { + pos++; + continue; + } + + // Get next phoneme + X++; + A = phonemeindex[X]; + //pos41841 + // Is the next phoneme a pause? + if(A != 0) { + // If next phoneme is not a pause, continue processing phonemes + if((flags[A] & 128) == 0) { + pos++; + continue; + } + // If next phoneme is stressed, continue processing phonemes + // FIXME: How does a pause get stressed? + if(stress[X] != 0) { + pos++; + continue; + } + //pos41856: + // Set phonemes to DX + + phonemeindex[pos] = 30; // 'DX' + } else { + A = phonemeindex[X + 1]; + if(A == 255) //prevent buffer overflow + A = 65 & 128; + else + // Is next phoneme a vowel or ER? + A = flags[A] & 128; + + if(A != 0) phonemeindex[pos] = 30; // 'DX' + } + + pos++; + + } // while +} // parser 2 + +// Applies various rules that adjust the lengths of phonemes +// +// Lengthen or between and by 1.5 +// - decrease length by 1 +// - decrease vowel by 1/8th +// - increase vowel by 1/2 + 1 +// - set nasal = 5, consonant = 6 +// {optional silence} - shorten both to 1/2 + 1 +// - decrease by 2 + +//void Code48619() +void STM32SAM::AdjustLengths() { + // LENGTHEN VOWELS PRECEDING PUNCTUATION + // + // Search for punctuation. If found, back up to the first vowel, then + // process all phonemes between there and up to (but not including) the punctuation. + // If any phoneme is found that is a either a fricative or voiced, the duration is + // increased by (length * 1.5) + 1 + + // loop index + X = 0; + unsigned char index; + + // iterate through the phoneme list + unsigned char loopIndex = 0; + while(1) { + // get a phoneme + index = phonemeindex[X]; + + // exit loop if end on buffer token + if(index == 255) break; + + // not punctuation? + if((flags2[index] & 1) == 0) { + // skip + X++; + continue; + } + + // hold index + loopIndex = X; + + // Loop backwards from this point + pos48644: + + // back up one phoneme + X--; + + // stop once the beginning is reached + if(X == 0) break; + + // get the preceding phoneme + index = phonemeindex[X]; + + if(index != 255) //inserted to prevent access overrun + if((flags[index] & 128) == 0) goto pos48644; // if not a vowel, continue looping + + //pos48657: + do { + // test for vowel + index = phonemeindex[X]; + + if(index != 255) //inserted to prevent access overrun + // test for fricative/unvoiced or not voiced + if(((flags2[index] & 32) == 0) || ((flags[index] & 4) != 0)) //nochmal �berpr�fen + { + //A = flags[Y] & 4; + //if(A == 0) goto pos48688; + + // get the phoneme length + A = phonemeLength[X]; + + // change phoneme length to (length * 1.5) + 1 + A = (A >> 1) + A + 1; + + phonemeLength[X] = A; + } + // keep moving forward + X++; + } while(X != loopIndex); + // if (X != loopIndex) goto pos48657; + X++; + } // while + + // Similar to the above routine, but shorten vowels under some circumstances + + // Loop throught all phonemes + loopIndex = 0; + //pos48697 + + while(1) { + // get a phoneme + X = loopIndex; + index = phonemeindex[X]; + + // exit routine at end token + if(index == 255) return; + + // vowel? + A = flags[index] & 128; + if(A != 0) { + // get next phoneme + X++; + index = phonemeindex[X]; + + // get flags + if(index == 255) + mem56 = 65; // use if end marker + else + mem56 = flags[index]; + + // not a consonant + if((flags[index] & 64) == 0) { + // RX or LX? + if((index == 18) || (index == 19)) // 'RX' & 'LX' + { + // get the next phoneme + X++; + index = phonemeindex[X]; + + // next phoneme a consonant? + if((flags[index] & 64) != 0) { + // RULE: RX | LX + + // decrease length of vowel by 1 frame + phonemeLength[loopIndex]--; + } + // move ahead + loopIndex++; + continue; + } + // move ahead + loopIndex++; + continue; + } + + // Got here if not + + // not voiced + if((mem56 & 4) == 0) { + // Unvoiced + // *, .*, ?*, ,*, -*, DX, S*, SH, F*, TH, /H, /X, CH, P*, T*, K*, KX + + // not an unvoiced plosive? + if((mem56 & 1) == 0) { + // move ahead + loopIndex++; + continue; + } + + // P*, T*, K*, KX + + // RULE: + // + + // move back + X--; + + // decrease length by 1/8th + mem56 = phonemeLength[X] >> 3; + phonemeLength[X] -= mem56; + + // move ahead + loopIndex++; + continue; + } + + // RULE: + // + + // decrease length + A = phonemeLength[X - 1]; + phonemeLength[X - 1] = (A >> 2) + A + 1; // 5/4*A + 1 + + // move ahead + loopIndex++; + continue; + } + + // WH, R*, L*, W*, Y*, M*, N*, NX, Q*, Z*, ZH, V*, DH, J*, B*, D*, G*, GX + + //pos48821: + + // RULE: + // Set punctuation length to 6 + // Set stop consonant length to 5 + + // nasal? + if((flags2[index] & 8) != 0) { + // M*, N*, NX, + + // get the next phoneme + X++; + index = phonemeindex[X]; + + // end of buffer? + if(index == 255) + A = 65 & 2; //prevent buffer overflow + else + A = flags[index] & 2; // check for stop consonant + + // is next phoneme a stop consonant? + if(A != 0) + + // B*, D*, G*, GX, P*, T*, K*, KX + + { + // set stop consonant length to 6 + phonemeLength[X] = 6; + + // set nasal length to 5 + phonemeLength[X - 1] = 5; + } + // move to next phoneme + loopIndex++; + continue; + } + + // WH, R*, L*, W*, Y*, Q*, Z*, ZH, V*, DH, J*, B*, D*, G*, GX + + // RULE: {optional silence} + // Shorten both to (length/2 + 1) + + // (voiced) stop consonant? + if((flags[index] & 2) != 0) { + // B*, D*, G*, GX + + // move past silence + do { + // move ahead + X++; + index = phonemeindex[X]; + } while(index == 0); + + // check for end of buffer + if(index == 255) //buffer overflow + { + // ignore, overflow code + if((65 & 2) == 0) { + loopIndex++; + continue; + } + } else if((flags[index] & 2) == 0) { + // if another stop consonant, move ahead + loopIndex++; + continue; + } + + // RULE: {optional silence} + + // X gets overwritten, so hold prior X value for debug statement + // int debugX = X; + // shorten the prior phoneme length to (length/2 + 1) + phonemeLength[X] = (phonemeLength[X] >> 1) + 1; + X = loopIndex; + + // also shorten this phoneme length to (length/2 +1) + phonemeLength[loopIndex] = (phonemeLength[loopIndex] >> 1) + 1; + + // move ahead + loopIndex++; + continue; + } + + // WH, R*, L*, W*, Y*, Q*, Z*, ZH, V*, DH, J*, **, + + // RULE: + // Decrease by 2 + + // liquic consonant? + if((flags2[index] & 16) != 0) { + // R*, L*, W*, Y* + + // get the prior phoneme + index = phonemeindex[X - 1]; + + // prior phoneme a stop consonant> + if((flags[index] & 2) != 0) { + // Rule: + + // decrease the phoneme length by 2 frames (20 ms) + phonemeLength[X] -= 2; + } + } + + // move to next phoneme + loopIndex++; + continue; + } + // goto pos48701; +} + +// ------------------------------------------------------------------------- +// ML : Code47503 is division with remainder, and mem50 gets the sign +void STM32SAM::Code47503(unsigned char mem52) { + Y = 0; + if((mem53 & 128) != 0) { + mem53 = -mem53; + Y = 128; + } + mem50 = Y; + A = 0; + for(X = 8; X > 0; X--) { + int temp = mem53; + mem53 = mem53 << 1; + A = A << 1; + if(temp >= 128) A++; + if(A >= mem52) { + A = A - mem52; + mem53++; + } + } + + mem51 = A; + if((mem50 & 128) != 0) mem53 = -mem53; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Reciter +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::Code37055(unsigned char mem59) { + X = mem59; + X--; + A = inputtemp[X]; + Y = A; + A = tab36376[Y]; + return; +} + +void STM32SAM::Code37066(unsigned char mem58) { + X = mem58; + X++; + A = inputtemp[X]; + Y = A; + A = tab36376[Y]; +} + +unsigned char STM32SAM::GetRuleByte(unsigned short mem62, unsigned char Y) { + unsigned int address = mem62; + + if(mem62 >= 37541) { + address -= 37541; + return rules2[address + Y]; + } + address -= 32000; + return rules[address + Y]; +} + +int STM32SAM::TextToPhonemes(unsigned char* input) // Code36484 +{ + //unsigned char *tab39445 = &mem[39445]; //input and output + //unsigned char mem29; + unsigned char mem56; //output position for phonemes + unsigned char mem57; + unsigned char mem58; + unsigned char mem59; + unsigned char mem60; + unsigned char mem61; + unsigned short mem62; // memory position of current rule + + unsigned char mem64; // position of '=' or current character + unsigned char mem65; // position of ')' + unsigned char mem66; // position of '(' + unsigned char mem36653; + + inputtemp[0] = 32; + + // secure copy of input + // because input will be overwritten by phonemes + X = 1; + Y = 0; + do { + //pos36499: + A = input[Y] & 127; + if(A >= 112) + A = A & 95; + else if(A >= 96) + A = A & 79; + + inputtemp[X] = A; + X++; + Y++; + } while(Y != 255); + + X = 255; + inputtemp[X] = 27; + mem61 = 255; + +pos36550: + A = 255; + mem56 = 255; + +pos36554: + while(1) { + mem61++; + X = mem61; + A = inputtemp[X]; + mem64 = A; + if(A == '[') { + mem56++; + X = mem56; + A = 155; + input[X] = 155; + //goto pos36542; + // Code39771(); //Code39777(); + return 1; + } + + //pos36579: + if(A != '.') break; + X++; + Y = inputtemp[X]; + A = tab36376[Y] & 1; + if(A != 0) break; + mem56++; + X = mem56; + A = '.'; + input[X] = '.'; + } //while + + //pos36607: + A = mem64; + Y = A; + A = tab36376[A]; + mem57 = A; + if((A & 2) != 0) { + mem62 = 37541; + goto pos36700; + } + + //pos36630: + A = mem57; + if(A != 0) goto pos36677; + A = 32; + inputtemp[X] = ' '; + mem56++; + X = mem56; + if(X > 120) goto pos36654; + input[X] = A; + goto pos36554; + + // ----- + + //36653 is unknown. Contains position + +pos36654: + input[X] = 155; + A = mem61; + mem36653 = A; + // mem29 = A; // not used + // Code36538(); das ist eigentlich + return 1; + //Code39771(); + //go on if there is more input ??? + mem61 = mem36653; + goto pos36550; + +pos36677: + A = mem57 & 128; + if(A == 0) { + //36683: BRK + return 0; + } + + // go to the right rules for this character. + X = mem64 - 'A'; + mem62 = tab37489[X] | (tab37515[X] << 8); + + // ------------------------------------- + // go to next rule + // ------------------------------------- + +pos36700: + + // find next rule + Y = 0; + do { + mem62 += 1; + A = GetRuleByte(mem62, Y); + } while((A & 128) == 0); + Y++; + + //pos36720: + // find '(' + while(1) { + A = GetRuleByte(mem62, Y); + if(A == '(') break; + Y++; + } + mem66 = Y; + + //pos36732: + // find ')' + do { + Y++; + A = GetRuleByte(mem62, Y); + } while(A != ')'); + mem65 = Y; + + //pos36741: + // find '=' + do { + Y++; + A = GetRuleByte(mem62, Y); + A = A & 127; + } while(A != '='); + mem64 = Y; + + X = mem61; + mem60 = X; + + // compare the string within the bracket + Y = mem66; + Y++; + //pos36759: + while(1) { + mem57 = inputtemp[X]; + A = GetRuleByte(mem62, Y); + if(A != mem57) goto pos36700; + Y++; + if(Y == mem65) break; + X++; + mem60 = X; + } + + // the string in the bracket is correct + + //pos36787: + A = mem61; + mem59 = mem61; + +pos36791: + while(1) { + mem66--; + Y = mem66; + A = GetRuleByte(mem62, Y); + mem57 = A; + //36800: BPL 36805 + if((A & 128) != 0) goto pos37180; + X = A & 127; + A = tab36376[X] & 128; + if(A == 0) break; + X = mem59 - 1; + A = inputtemp[X]; + if(A != mem57) goto pos36700; + mem59 = X; + } + + //pos36833: + A = mem57; + if(A == ' ') goto pos36895; + if(A == '#') goto pos36910; + if(A == '.') goto pos36920; + if(A == '&') goto pos36935; + if(A == '@') goto pos36967; + if(A == '^') goto pos37004; + if(A == '+') goto pos37019; + if(A == ':') goto pos37040; + // Code42041(); //Error + //36894: BRK + return 0; + + // -------------- + +pos36895: + Code37055(mem59); + A = A & 128; + if(A != 0) goto pos36700; +pos36905: + mem59 = X; + goto pos36791; + + // -------------- + +pos36910: + Code37055(mem59); + A = A & 64; + if(A != 0) goto pos36905; + goto pos36700; + + // -------------- + +pos36920: + Code37055(mem59); + A = A & 8; + if(A == 0) goto pos36700; +pos36930: + mem59 = X; + goto pos36791; + + // -------------- + +pos36935: + Code37055(mem59); + A = A & 16; + if(A != 0) goto pos36930; + A = inputtemp[X]; + if(A != 72) goto pos36700; + X--; + A = inputtemp[X]; + if((A == 67) || (A == 83)) goto pos36930; + goto pos36700; + + // -------------- + +pos36967: + Code37055(mem59); + A = A & 4; + if(A != 0) goto pos36930; + A = inputtemp[X]; + if(A != 72) goto pos36700; + if((A != 84) && (A != 67) && (A != 83)) goto pos36700; + mem59 = X; + goto pos36791; + + // -------------- + +pos37004: + Code37055(mem59); + A = A & 32; + if(A == 0) goto pos36700; + +pos37014: + mem59 = X; + goto pos36791; + + // -------------- + +pos37019: + X = mem59; + X--; + A = inputtemp[X]; + if((A == 'E') || (A == 'I') || (A == 'Y')) goto pos37014; + goto pos36700; + // -------------- + +pos37040: + Code37055(mem59); + A = A & 32; + if(A == 0) goto pos36791; + mem59 = X; + goto pos37040; + + //--------------------------------------- + +pos37077: + X = mem58 + 1; + A = inputtemp[X]; + if(A != 'E') goto pos37157; + X++; + Y = inputtemp[X]; + X--; + A = tab36376[Y] & 128; + if(A == 0) goto pos37108; + X++; + A = inputtemp[X]; + if(A != 'R') goto pos37113; +pos37108: + mem58 = X; + goto pos37184; +pos37113: + if((A == 83) || (A == 68)) goto pos37108; // 'S' 'D' + if(A != 76) goto pos37135; // 'L' + X++; + A = inputtemp[X]; + if(A != 89) goto pos36700; + goto pos37108; + +pos37135: + if(A != 70) goto pos36700; + X++; + A = inputtemp[X]; + if(A != 85) goto pos36700; + X++; + A = inputtemp[X]; + if(A == 76) goto pos37108; + goto pos36700; + +pos37157: + if(A != 73) goto pos36700; + X++; + A = inputtemp[X]; + if(A != 78) goto pos36700; + X++; + A = inputtemp[X]; + if(A == 71) goto pos37108; + //pos37177: + goto pos36700; + + // ----------------------------------------- + +pos37180: + + A = mem60; + mem58 = A; + +pos37184: + Y = mem65 + 1; + + //37187: CPY 64 + // if(? != 0) goto pos37194; + if(Y == mem64) goto pos37455; + mem65 = Y; + //37196: LDA (62),y + A = GetRuleByte(mem62, Y); + mem57 = A; + X = A; + A = tab36376[X] & 128; + if(A == 0) goto pos37226; + X = mem58 + 1; + A = inputtemp[X]; + if(A != mem57) goto pos36700; + mem58 = X; + goto pos37184; +pos37226: + A = mem57; + if(A == 32) goto pos37295; // ' ' + if(A == 35) goto pos37310; // '#' + if(A == 46) goto pos37320; // '.' + if(A == 38) goto pos37335; // '&' + if(A == 64) goto pos37367; // '' + if(A == 94) goto pos37404; // '' + if(A == 43) goto pos37419; // '+' + if(A == 58) goto pos37440; // ':' + if(A == 37) goto pos37077; // '%' + //pos37291: + // Code42041(); //Error + //37294: BRK + return 0; + + // -------------- +pos37295: + Code37066(mem58); + A = A & 128; + if(A != 0) goto pos36700; +pos37305: + mem58 = X; + goto pos37184; + + // -------------- + +pos37310: + Code37066(mem58); + A = A & 64; + if(A != 0) goto pos37305; + goto pos36700; + + // -------------- + +pos37320: + Code37066(mem58); + A = A & 8; + if(A == 0) goto pos36700; + +pos37330: + mem58 = X; + goto pos37184; + + // -------------- + +pos37335: + Code37066(mem58); + A = A & 16; + if(A != 0) goto pos37330; + A = inputtemp[X]; + if(A != 72) goto pos36700; + X++; + A = inputtemp[X]; + if((A == 67) || (A == 83)) goto pos37330; + goto pos36700; + + // -------------- + +pos37367: + Code37066(mem58); + A = A & 4; + if(A != 0) goto pos37330; + A = inputtemp[X]; + if(A != 72) goto pos36700; + if((A != 84) && (A != 67) && (A != 83)) goto pos36700; + mem58 = X; + goto pos37184; + + // -------------- + +pos37404: + Code37066(mem58); + A = A & 32; + if(A == 0) goto pos36700; +pos37414: + mem58 = X; + goto pos37184; + + // -------------- + +pos37419: + X = mem58; + X++; + A = inputtemp[X]; + if((A == 69) || (A == 73) || (A == 89)) goto pos37414; + goto pos36700; + + // ---------------------- + +pos37440: + + Code37066(mem58); + A = A & 32; + if(A == 0) goto pos37184; + mem58 = X; + goto pos37440; +pos37455: + Y = mem64; + mem61 = mem60; + +pos37461: + //37461: LDA (62),y + A = GetRuleByte(mem62, Y); + mem57 = A; + A = A & 127; + if(A != '=') { + mem56++; + X = mem56; + input[X] = A; + } + + //37478: BIT 57 + //37480: BPL 37485 //not negative flag + if((mem57 & 128) == 0) goto pos37485; //??? + goto pos36554; +pos37485: + Y++; + goto pos37461; +} + +// Constructor + +STM32SAM::STM32SAM(uint32_t STM32SAM_SPEED /* = 5 */) { + STM32SAM_SPEED = STM32SAM_SPEED & 0x1f; // limit it from 0 to 31 + + _STM32SAM_SPEED = STM32SAM_SPEED; + + // set default voice + + speed = 72; + pitch = 64; + mouth = 128; + throat = 128; + + phonetic = 0; + singmode = 0; + + wait1 = 7; + wait2 = 6; + + mem59 = 0; + + oldtimetableindex = 0; +} + +STM32SAM::STM32SAM() { + _STM32SAM_SPEED = 7; + + // set default voice + + speed = 72; + pitch = 64; + mouth = 128; + throat = 128; + + phonetic = 0; + singmode = 0; + + wait1 = 7; + wait2 = 6; + + mem59 = 0; + + oldtimetableindex = 0; +} + +/* + STM32SAM::~STM32SAM() { + { + // TODO: end(); + } +*/ + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM sam (variable string, phonetic, sing, pitch, speed, mouth, throat) +// STM32SAM say (sing off, phonetic off) (const string) +// STM32SAM say (sing off, phonetic off) (variable string) +// STM32SAM sing (sing on, phonetic off) (const string) +// STM32SAM sing (sing on, phonetic off) (variable string) +// STM32SAM sayPhonetic (sing off, phonetic on) (const string) +// STM32SAM sayPhonetic (sing off, phonetic on) (variable string) +// STM32SAM singPhonetic (sing on, phonetic on) (const string) +// STM32SAM singPhonetic (sing on, phonetic on) (variable string) +// STM32SAM voice (pitch, speed, mouth, throat) +// STM32SAM setPitch (pitch) +// STM32SAM setSpeed (speed) +// STM32SAM setMouth (mouth) +// STM32SAM setThroat (throat) +// +// +//////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM sam (const string, phonetic, sing, pitch, speed, mouth, throat) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +char to_upper_case(char c) { + if(c >= 'a' && c <= 'z') { + return c - 'a' + 'A'; + } + return c; +} + +void STM32SAM::sam( + const char* argv, + unsigned char _phonetic, + unsigned char _singmode, + unsigned char _pitch, + unsigned char _speed, + unsigned char _mouth, + unsigned char _throat) { + phonetic = _phonetic; + singmode = _singmode; + pitch = _pitch; + speed = _speed; + mouth = _mouth; + throat = _throat; + + int i; + + for(i = 0; i < 256; i++) { + input[i] = argv[i]; + } + + for(i = 0; input[i] != 0; i++) { + if(i != 0) { + input[i] = to_upper_case((int)argv[i]); + } + } + + if(!phonetic) { + strncat(input, "[", 256); + if(!TextToPhonemes((unsigned char*)input)) { + // PrintUsage(); + return; + } + + } else { + strncat(input, "\x9b", 256); + } + + SetInput(input); + + if(!SAMMain()) { + return; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM sam (variable string, phonetic, sing, pitch, speed, mouth, throat) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::sam( + char* argv, + unsigned char _phonetic, + unsigned char _singmode, + unsigned char _pitch, + unsigned char _speed, + unsigned char _mouth, + unsigned char _throat) { + phonetic = _phonetic; + singmode = _singmode; + pitch = _pitch; + speed = _speed; + mouth = _mouth; + throat = _throat; + + int i; + + for(i = 0; i < 256; i++) { + input[i] = argv[i]; + } + + for(i = 0; input[i] != 0; i++) { + if(i != 0) { + input[i] = to_upper_case((int)argv[i]); + } + } + + if(!phonetic) { + strncat(input, "[", 256); + if(!TextToPhonemes((unsigned char*)input)) { + // PrintUsage(); + return; + } + + } else { + strncat(input, "\x9b", 256); + } + + SetInput(input); + + if(!SAMMain()) { + return; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM say(sing off, phonetic off) (const string) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::say(const char* argv) { + int i; + + phonetic = 0; + singmode = 0; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +void STM32SAM::say(char* argv) { + int i; + + phonetic = 0; + singmode = 0; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM sing (sing on, phonetic off) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::sing(const char* argv) { + int i; + + phonetic = 0; + singmode = 1; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +void STM32SAM::sing(char* argv) { + int i; + + phonetic = 0; + singmode = 1; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM sayPhonetic (sing off, phonetic on) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::sayPhonetic(const char* argv) { + int i; + + phonetic = 1; + singmode = 0; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +void STM32SAM::sayPhonetic(char* argv) { + int i; + + phonetic = 1; + singmode = 0; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM singPhonetic (sing on, phonetic on) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::singPhonetic(const char* argv) { + int i; + + phonetic = 1; + singmode = 1; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +void STM32SAM::singPhonetic(char* argv) { + int i; + + phonetic = 1; + singmode = 0; + + char const_input[256]; + + for(i = 0; i < 256; i++) { + const_input[i] = argv[i]; + } + + sam(const_input, phonetic, singmode, pitch, speed, mouth, throat); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM voice (pitch, speed, mouth, throat) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::setVoice( + unsigned char _pitch /* = 64 */, + unsigned char _speed /* = 72 */, + unsigned char _mouth /* = 128 */, + unsigned char _throat /* = 128 */) { + pitch = _pitch; + speed = _speed; + mouth = _mouth; + throat = _throat; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM setPitch (pitch) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::setPitch(unsigned char _pitch /* = 64 */) { + pitch = _pitch; +} +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM setSpeed (speed) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::setSpeed(unsigned char _speed /* = 72 */) { + speed = _speed; +} +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM setMouth (mouth) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::setMouth(unsigned char _mouth /* = 128 */) { + mouth = _mouth; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// STM32SAM setThroat (throat) +// +//////////////////////////////////////////////////////////////////////////////////////////// + +void STM32SAM::setThroat(unsigned char _throat /* = 128 */) { + throat = _throat; +} +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Hardware +// +//////////////////////////////////////////////////////////////////////////////////////////// +// Hardware specifics, for easier porting to other microcontrollers + +// +// Set PA8 pin as PWM, at 256 timer ticks overflow (8bit resolution) + +#include +#include + +#define FURI_HAL_SPEAKER_TIMER TIM16 +#define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1 + +void STM32SAM::begin(void) { +#ifdef USE_ROGER_CORE + + pinMode(PA8, PWM); // audio output pin + + Timer1.setPeriod( + 4); // Can't set at 256 ticks, only in uS. First nearest uS is 4 (Roger core is only for bluepill, that means 72*4=288 ticks, or 128*4=512 ticks when overclocked. It's ok, just overall volume will be lower, because maximum volume will be 256/288 or 256/512) + +#endif + +#ifdef USE_STM32duino_CORE + pinMode(PA8, OUTPUT); + + PWM->pause(); + PWM->setMode(1, TIMER_OUTPUT_COMPARE_PWM1, PA8); // TIM1 CH1 (PA8) + PWM->setPrescaleFactor(1); + PWM->setOverflow(256, TICK_FORMAT); // 256 ticks overflow, no matter the CPU (timer) speed + PWM->resume(); + +#endif + + LL_TIM_InitTypeDef TIM_InitStruct; + memset(&TIM_InitStruct, 0, sizeof(LL_TIM_InitTypeDef)); + TIM_InitStruct.Prescaler = 4; + TIM_InitStruct.Autoreload = 255; + LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct); + + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct; + memset(&TIM_OC_InitStruct, 0, sizeof(LL_TIM_OC_InitTypeDef)); + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.CompareValue = 127; + LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct); + + LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER); + LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER); +} // begin + +inline void STM32SAM::SetAUDIO(unsigned char main_volume) { +#ifdef USE_ROGER_CORE + Timer1.setCompare(TIMER_CH1, main_volume); +#endif + +#ifdef USE_STM32duino_CORE + PWM->setCaptureCompare(1, main_volume, TICK_COMPARE_FORMAT); +#endif + + // if(main_volume > 64) { + // LL_TIM_OC_SetCompareCH1(FURI_HAL_SPEAKER_TIMER, 127); + // } else { + // LL_TIM_OC_SetCompareCH1(FURI_HAL_SPEAKER_TIMER, main_volume); + // } + + float data = main_volume; + data /= 255.0f; + data -= 0.5f; + data *= 4.0f; + data = tanhf(data); + + data += 0.5f; + data *= 255.0f; + + if(data < 0) { + data = 0; + } else if(data > 255) { + data = 255; + } + + LL_TIM_OC_SetCompareCH1(FURI_HAL_SPEAKER_TIMER, data); +} \ No newline at end of file diff --git a/applications/plugins/sam/stm32_sam.h b/applications/plugins/sam/stm32_sam.h new file mode 100644 index 000000000..910227ac3 --- /dev/null +++ b/applications/plugins/sam/stm32_sam.h @@ -0,0 +1,96 @@ +#include + +#ifndef __STM32SAM__ +#define __STM32SAM__ + +// SAM Text-To-Speech (TTS), ported from https://github.com/s-macke/SAM + +class STM32SAM { +public: + STM32SAM(uint32_t STM32SAM_SPEED); + STM32SAM(); + + void begin(void); + + void + sam(const char* argv, + unsigned char phonetic, + unsigned char singmode, + unsigned char pitch, + unsigned char speed, + unsigned char mouth, + unsigned char throat); + void + sam(char* argv, + unsigned char phonetic, + unsigned char singmode, + unsigned char pitch, + unsigned char speed, + unsigned char mouth, + unsigned char throat); + + void say(const char* argv); + void say(char* argv); + void sing(const char* argv); + void sing(char* argv); + void sayPhonetic(const char* argv); + void sayPhonetic(char* argv); + void singPhonetic(const char* argv); + void singPhonetic(char* argv); + void setVoice( + unsigned char _pitch = 64, + unsigned char _speed = 72, + unsigned char _mouth = 128, + unsigned char _throat = 128); + void setPitch(unsigned char _pitch = 64); + void setSpeed(unsigned char _speed = 72); + void setMouth(unsigned char _mouth = 128); + void setThroat(unsigned char _throat = 128); + +private: + void SetAUDIO(unsigned char main_volume); + + void Output8BitAry(int index, unsigned char ary[5]); + void Output8Bit(int index, unsigned char A); + unsigned char Read(unsigned char p, unsigned char Y); + void Write(unsigned char p, unsigned char Y, unsigned char value); + void RenderSample(unsigned char* mem66); + void Render(); + void AddInflection(unsigned char mem48, unsigned char phase1); + void SetMouthThroat(); + unsigned char trans(unsigned char mem39212, unsigned char mem39213); + void SetInput(char* _input); + void Init(); + int SAMMain(); + void PrepareOutput(); + void Insert( + unsigned char position /*var57*/, + unsigned char mem60, + unsigned char mem59, + unsigned char mem58); + void InsertBreath(); + void CopyStress(); + int Parser1(); + void SetPhonemeLength(); + void Code41240(); + void Parser2(); + void AdjustLengths(); + void Code47503(unsigned char mem52); + void Code37055(unsigned char mem59); + void Code37066(unsigned char mem58); + unsigned char GetRuleByte(unsigned short mem62, unsigned char Y); + int TextToPhonemes(unsigned char* input); // Code36484 + + uint32_t _STM32SAM_SPEED; + + unsigned char speed; + unsigned char pitch; + unsigned char mouth; + unsigned char throat; + + unsigned char phonetic; + unsigned char singmode; + +}; // STM32SAM class + +#endif \ No newline at end of file