Flipper/Applications/Official/DEV_FW/source/xMasterX/sam/stm32_sam.cpp

5704 lines
172 KiB
C++
Raw Normal View History

2023-01-26 07:52:38 +00:00
#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 <length> 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 (<28>) 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:
//
// <DIPHTONG ENDING WITH WX> -> <DIPHTONG ENDING WITH WX> WX
// <DIPHTONG NOT ENDING WITH WX> -> <DIPHTONG NOT ENDING WITH WX> YX
// UL -> AX L
// UM -> AX M
// <STRESSED VOWEL> <SILENCE> <STRESSED VOWEL> -> <STRESSED VOWEL> <SILENCE> Q <VOWEL>
// T R -> CH R
// D R -> J R
// <VOWEL> R -> <VOWEL> RX
// <VOWEL> L -> <VOWEL> LX
// G S -> G Z
// K <VOWEL OR DIPHTONG NOT ENDING WITH IY> -> KX <VOWEL OR DIPHTONG NOT ENDING WITH IY>
// G <VOWEL OR DIPHTONG NOT ENDING WITH IY> -> GX <VOWEL OR DIPHTONG NOT ENDING WITH IY>
// S P -> S B
// S T -> S D
// S K -> S G
// S KX -> S GX
// <ALVEOLAR> UW -> <ALVEOLAR> UX
// CH -> CH CH' (CH requires two phonemes to represent it)
// J -> J J' (J requires two phonemes to represent it)
// <UNSTRESSED VOWEL> T <PAUSE> -> <UNSTRESSED VOWEL> DX <PAUSE>
// <UNSTRESSED VOWEL> D <PAUSE> -> <UNSTRESSED VOWEL> DX <PAUSE>
//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:
// <DIPHTONG ENDING WITH WX> -> <DIPHTONG ENDING WITH WX> WX
// <DIPHTONG NOT ENDING WITH WX> -> <DIPHTONG NOT ENDING WITH 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:
// <STRESSED VOWEL> <SILENCE> <STRESSED VOWEL> -> <STRESSED VOWEL> <SILENCE> Q <VOWEL>
// 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
// <VOWEL> R -> <VOWEL> 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:
// <VOWEL> L -> <VOWEL> 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 <VOWEL OR DIPHTONG NOT ENDING WITH IY> -> KX <VOWEL OR DIPHTONG NOT ENDING WITH IY>
// 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 <VOWEL OR DIPHTONG NOT ENDING WITH IY> -> GX <VOWEL OR DIPHTONG NOT ENDING WITH IY>
// 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:
// <ALVEOLAR> UW -> <ALVEOLAR> 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"
// <UNSTRESSED VOWEL> T <PAUSE> -> <UNSTRESSED VOWEL> DX <PAUSE>
// <UNSTRESSED VOWEL> D <PAUSE> -> <UNSTRESSED VOWEL> DX <PAUSE>
// 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 <FRICATIVE> or <VOICED> between <VOWEL> and <PUNCTUATION> by 1.5
// <VOWEL> <RX | LX> <CONSONANT> - decrease <VOWEL> length by 1
// <VOWEL> <UNVOICED PLOSIVE> - decrease vowel by 1/8th
// <VOWEL> <UNVOICED CONSONANT> - increase vowel by 1/2 + 1
// <NASAL> <STOP CONSONANT> - set nasal = 5, consonant = 6
// <VOICED STOP CONSONANT> {optional silence} <STOP CONSONANT> - shorten both to 1/2 + 1
// <LIQUID CONSONANT> <DIPHTONG> - 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 <20>berpr<70>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: <VOWEL> RX | LX <CONSONANT>
// decrease length of vowel by 1 frame
phonemeLength[loopIndex]--;
}
// move ahead
loopIndex++;
continue;
}
// move ahead
loopIndex++;
continue;
}
// Got here if not <VOWEL>
// 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: <VOWEL> <UNVOICED PLOSIVE>
// <VOWEL> <P*, T*, K*, KX>
// move back
X--;
// decrease length by 1/8th
mem56 = phonemeLength[X] >> 3;
phonemeLength[X] -= mem56;
// move ahead
loopIndex++;
continue;
}
// RULE: <VOWEL> <VOICED CONSONANT>
// <VOWEL> <WH, R*, L*, W*, Y*, M*, N*, NX, DX, Q*, Z*, ZH, V*, DH, J*, B*, D*, G*, GX>
// 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: <NASAL> <STOP CONSONANT>
// 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: <VOICED STOP CONSONANT> {optional silence} <STOP CONSONANT>
// 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: <UNVOICED STOP CONSONANT> {optional silence} <STOP CONSONANT>
// 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: <VOICED NON-VOWEL> <DIPHTONG>
// Decrease <DIPHTONG> 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: <LIQUID CONSONANT> <DIPHTONG>
// 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 <math.h>
#include <stm32wbxx_ll_tim.h>
#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);
}