#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "debug.h"
#include "sam.h"
#include "render.h"
#include "SamTabs.h"
char input[256]; unsigned char speed = 72;
unsigned char pitch = 64;
unsigned char mouth = 128;
unsigned char throat = 128;
int singmode = 0;
extern int sam_debug;
unsigned char mem39;
unsigned char mem44;
unsigned char mem47;
unsigned char mem49;
unsigned char mem50;
unsigned char mem51;
unsigned char mem53;
unsigned char mem56;
unsigned char mem59=0;
unsigned char B, R, S;
unsigned char stress[256]; unsigned char phonemeLength[256]; unsigned char phonemeindex[256];
unsigned char phonemeIndexOutput[60]; unsigned char stressOutput[60]; unsigned char phonemeLengthOutput[60];
int bufferpos=0;
char *buffer = NULL;
void 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;
}
void SetSpeed(unsigned char _speed) {speed = _speed;}
void SetPitch(unsigned char _pitch) {pitch = _pitch;}
void SetMouth(unsigned char _mouth) {mouth = _mouth;}
void SetThroat(unsigned char _throat) {throat = _throat;}
void EnableSingmode() {singmode = 1;}
char* GetBuffer(){return buffer;}
int GetBufferLength(){return bufferpos;}
void Init();
int Parser1();
void Parser2();
int SAMMain();
void CopyStress();
void SetPhonemeLength();
void AdjustLengths();
void Code41240();
void Insert(unsigned char position, unsigned char mem60, unsigned char mem59, unsigned char mem58);
void InsertBreath();
void PrepareOutput();
void SetMouthThroat(unsigned char mouth, unsigned char throat);
void Init()
{
int i;
SetMouthThroat( mouth, throat);
bufferpos = 0;
buffer = malloc(22050*10);
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;
}
int SAMMain()
{
Init();
phonemeindex[255] = 32;
if (!Parser1()) return 0;
if (sam_debug)
PrintPhonemes(phonemeindex, phonemeLength, stress);
Parser2();
CopyStress();
SetPhonemeLength();
AdjustLengths();
Code41240();
do
{
B = phonemeindex[R];
if (B > 80)
{
phonemeindex[R] = 255;
break; }
R++;
} while (R != 0);
InsertBreath();
if (sam_debug)
{
PrintPhonemes(phonemeindex, phonemeLength, stress);
}
PrepareOutput();
return 1;
}
void PrepareOutput()
{
B = 0;
R = 0;
S = 0;
while(1)
{
B = phonemeindex[R];
if (B == 255)
{
B = 255;
phonemeIndexOutput[S] = 255;
Render();
return;
}
if (B == 254)
{
R++;
int temp = R;
phonemeIndexOutput[S] = 255;
Render();
R=temp;
S = 0;
continue;
}
if (B == 0)
{
R++;
continue;
}
phonemeIndexOutput[S] = B;
phonemeLengthOutput[S] = phonemeLength[R];
stressOutput[S] = stress[R];
R++;
S++;
}
}
void InsertBreath()
{
unsigned char mem54;
unsigned char mem55;
unsigned char index; mem54 = 255;
R++;
mem55 = 0;
unsigned char mem66 = 0;
while(1)
{
R = mem66;
index = phonemeindex[R];
if (index == 255) return;
mem55 += phonemeLength[R];
if (mem55 < 232)
{
if (index != 254) {
B = flags2[index]&1;
if(B != 0)
{
R++;
mem55 = 0;
Insert(R, 254, mem59, 0);
mem66++;
mem66++;
continue;
}
}
if (index == 0) mem54 = R;
mem66++;
continue;
}
R = mem54;
phonemeindex[R] = 31; phonemeLength[R] = 4;
stress[R] = 0;
R++;
mem55 = 0;
Insert(R, 254, mem59, 0);
R++;
mem66 = R;
}
}
void CopyStress()
{
unsigned char pos=0; while(1)
{
S = phonemeindex[pos];
if (S == 255) return;
if ((flags[S] & 64) == 0) {pos++; continue;}
S = phonemeindex[pos+1];
if (S == 255) {
pos++; continue;
} else
if ((flags[S] & 128) == 0) {pos++; continue;}
S = stress[pos+1];
if (S == 0) {pos++; continue;}
if ((S & 128) != 0) {pos++; continue;}
stress[pos] = S+1;
pos++;
}
}
void Insert(unsigned char position, unsigned char mem60, unsigned char mem59, unsigned char mem58)
{
int i;
for(i=253; i >= position; i--) {
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;
}
int Parser1()
{
int i;
unsigned char sign1;
unsigned char sign2;
unsigned char position = 0;
R = 0;
B = 0;
S = 0;
for(i=0; i<256; i++)
stress[i] = 0;
while(1)
{
sign1 = input[R];
if (sign1 == 155)
{
phonemeindex[position] = 255; return 1; }
R++;
sign2 = input[R];
S = 0;
pos41095:
B = signInputTable1[S];
if (B == sign1)
{
B = signInputTable2[S];
if ((B != '*') && (B == sign2))
{
phonemeindex[position] = S;
position++;
R++;
continue;
}
}
S++;
if (S != 81) goto pos41095;
S = 0;
pos41134:
if (signInputTable2[S] == '*')
{
if (signInputTable1[S] == sign1)
{
phonemeindex[position] = S;
position++;
continue;
}
}
S++;
if (S != 81) goto pos41134;
S = 8;
while( (sign1 != stressInputTable[S]) && (S>0))
{
S--;
}
if (S == 0)
{
return 0;
}
stress[position-1] = S;
} }
void SetPhonemeLength()
{
unsigned char B;
int position = 0;
while(phonemeindex[position] != 255 )
{
B = stress[position];
if ((B == 0) || ((B&128) != 0))
{
phonemeLength[position] = phonemeLengthTable[phonemeindex[position]];
} else
{
phonemeLength[position] = phonemeStressedLengthTable[phonemeindex[position]];
}
position++;
}
}
void Code41240()
{
unsigned char pos=0;
while(phonemeindex[pos] != 255)
{
unsigned char index; R = 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
{
R++;
B = phonemeindex[R];
} while(B==0);
if (B != 255)
{
if ((flags[B] & 8) != 0) {pos++; continue;}
if ((B == 36) || (B == 37)) {pos++; continue;} }
Insert(pos+1, index+1, phonemeLengthTable[index+1], stress[pos]);
Insert(pos+2, index+2, phonemeLengthTable[index+2], stress[pos]);
pos += 3;
};
}
void Parser2()
{
if (sam_debug) fprintf(stderr,"Parser2\n");
unsigned char pos = 0; unsigned char mem58 = 0;
while(1)
{
R = pos;
B = phonemeindex[pos];
if (sam_debug && B != 255) fprintf(stderr,"%d: %c%c\n", R, signInputTable1[B], signInputTable2[B]);
if (B == 0)
{
pos++;
continue;
}
if (B == 255) return;
S = B;
if ((flags[B] & 16) == 0) goto pos41457;
mem58 = stress[pos];
B = flags[S] & 32;
if (B == 0) B = 20; else B = 21;
if (sam_debug) if (B==20) fprintf(stderr,"RULE: insert WX following diphtong NOT ending in IY sound\n");
if (sam_debug) if (B==21) fprintf(stderr,"RULE: insert YX following diphtong ending in IY sound\n");
Insert(pos+1, B, mem59, mem58);
R = pos;
goto pos41749;
pos41457:
B = phonemeindex[R];
if (B != 78) goto pos41487; B = 24;
if (sam_debug) fprintf(stderr,"RULE: UL -> AX L\n");
pos41466:
mem58 = stress[R];
phonemeindex[R] = 13; Insert(R+1, B, mem59, mem58);
pos++;
continue;
pos41487:
if (B != 79) goto pos41495; B = 27; if (sam_debug) fprintf(stderr,"RULE: UM -> AX M\n");
goto pos41466;
pos41495:
if (B != 80) goto pos41503;
B = 28; if (sam_debug) fprintf(stderr,"RULE: UN -> AX N\n");
goto pos41466;
pos41503:
S = B;
B = flags[B] & 128;
if (B != 0)
{
B = stress[R];
if (B != 0)
{
R++;
B = phonemeindex[R];
if (B == 0)
{
R++;
S = phonemeindex[R];
if (S == 255) B = 65&128;
else
B = flags[S] & 128;
if (B != 0)
{
B = stress[R];
if (B != 0)
{
if (sam_debug) fprintf(stderr,"RULE: Insert glottal stop between two stressed vowels with space between them\n");
Insert(R, 31, mem59, 0);
pos++;
continue;
}
}
}
}
}
R = pos;
B = phonemeindex[pos];
if (B != 23) goto pos41611;
R--;
B = phonemeindex[pos-1];
if (B == 69) {
if (sam_debug) fprintf(stderr,"RULE: T R -> CH R\n");
phonemeindex[pos-1] = 42;
goto pos41779;
}
if (B == 57) {
phonemeindex[pos-1] = 44;
if (sam_debug) fprintf(stderr,"RULE: D R -> J R\n");
goto pos41788;
}
B = flags[B] & 128;
if (sam_debug) fprintf(stderr,"RULE: R -> RX\n");
if (B != 0) phonemeindex[pos] = 18;
pos++;
continue;
pos41611:
if (B == 24) {
if ((flags[phonemeindex[pos-1]] & 128) == 0) {pos++; continue;}
if (sam_debug) fprintf(stderr,"RULE: <VOWEL> L -> <VOWEL> LX\n");
phonemeindex[R] = 19; pos++;
continue;
}
if (B == 32) {
if (phonemeindex[pos-1] != 60) {pos++; continue;}
if (sam_debug) fprintf(stderr,"RULE: G S -> G Z\n");
phonemeindex[pos] = 38; pos++;
continue;
}
if (B == 72) {
S = phonemeindex[pos+1];
if (S == 255) phonemeindex[pos] = 75; else
{
B = flags[S] & 32;
if (sam_debug) if (B==0) fprintf(stderr,"RULE: K <VOWEL OR DIPHTONG NOT ENDING WITH IY> -> KX <VOWEL OR DIPHTONG NOT ENDING WITH IY>\n");
if (B == 0) phonemeindex[pos] = 75; }
}
else
if (B == 60) {
unsigned char index = phonemeindex[pos+1];
if (index == 255) {
pos++; continue;
}
else
if ((flags[index] & 32) != 0) {pos++; continue;}
if (sam_debug) fprintf(stderr,"RULE: G <VOWEL OR DIPHTONG NOT ENDING WITH IY> -> GX <VOWEL OR DIPHTONG NOT ENDING WITH IY>\n");
phonemeindex[pos] = 63; pos++;
continue;
}
S = phonemeindex[pos];
B = flags[S] & 1;
if (B == 0) goto pos41749;
B = phonemeindex[pos-1];
if (B != 32) {
B = S;
goto pos41812;
}
if (sam_debug) fprintf(stderr,"RULE: S* %c%c -> S* %c%c\n", signInputTable1[S], signInputTable2[S],signInputTable1[S-12], signInputTable2[S-12]);
phonemeindex[pos] = S-12;
pos++;
continue;
pos41749:
B = phonemeindex[R];
if (B == 53) {
S = phonemeindex[R-1];
B = flags2[S] & 4;
if (B == 0) {pos++; continue;}
if (sam_debug) fprintf(stderr,"RULE: <ALVEOLAR> UW -> <ALVEOLAR> UX\n");
phonemeindex[R] = 16;
pos++;
continue;
}
pos41779:
if (B == 42) {
if (sam_debug) fprintf(stderr,"CH -> CH CH+1\n");
Insert(R+1, B+1, mem59, stress[R]);
pos++;
continue;
}
pos41788:
if (B == 44) {
if (sam_debug) fprintf(stderr,"J -> J J+1\n");
Insert(R+1, B+1, mem59, stress[R]);
pos++;
continue;
}
pos41812:
if (B != 69) if (B != 57) {pos++; continue;}
if ((flags[phonemeindex[R-1]] & 128) == 0) {pos++; continue;}
R++;
B = phonemeindex[R];
if (B != 0)
{
if ((flags[B] & 128) == 0) {pos++; continue;}
if (stress[R] != 0) {pos++; continue;}
if (sam_debug) fprintf(stderr,"RULE: Soften T or D following vowel or ER and preceding a pause -> DX\n");
phonemeindex[pos] = 30; } else
{
B = phonemeindex[R+1];
if (B == 255) B = 65 & 128;
else
B = flags[B] & 128;
if (sam_debug) if (B != 0) fprintf(stderr,"RULE: Soften T or D following vowel or ER and preceding a pause -> DX\n");
if (B != 0) phonemeindex[pos] = 30; }
pos++;
} }
void AdjustLengths()
{
R = 0;
unsigned char index;
unsigned char loopIndex=0;
while(1)
{
index = phonemeindex[R];
if (index == 255) break;
if((flags2[index] & 1) == 0)
{
R++;
continue;
}
loopIndex = R;
pos48644:
R--;
if(R == 0) break;
index = phonemeindex[R];
if (index != 255) if((flags[index] & 128) == 0) goto pos48644;
do
{
index = phonemeindex[R];
if (index != 255) if(((flags2[index] & 32) == 0) || ((flags[index] & 4) != 0)) {
B = phonemeLength[R];
B = (B >> 1) + B + 1;
if (sam_debug) fprintf(stderr,"RULE: Lengthen <FRICATIVE> or <VOICED> between <VOWEL> and <PUNCTUATION> by 1.5\n");
if (sam_debug) fprintf(stderr,"PRE\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
phonemeLength[R] = B;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
}
R++;
} while (R != loopIndex);
R++;
}
loopIndex = 0;
while(1)
{
R = loopIndex;
index = phonemeindex[R];
if (index == 255) return;
B = flags[index] & 128;
if (B != 0)
{
R++;
index = phonemeindex[R];
if (index == 255)
mem56 = 65; else
mem56 = flags[index];
if ((flags[index] & 64) == 0)
{
if ((index == 18) || (index == 19)) {
R++;
index = phonemeindex[R];
if ((flags[index] & 64) != 0) {
if (sam_debug) fprintf(stderr,"RULE: <VOWEL> <RX | LX> <CONSONANT> - decrease length by 1\n");
if (sam_debug) fprintf(stderr,"PRE\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", loopIndex, signInputTable1[phonemeindex[loopIndex]], signInputTable2[phonemeindex[loopIndex]], phonemeLength[loopIndex]);
phonemeLength[loopIndex]--;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", loopIndex, signInputTable1[phonemeindex[loopIndex]], signInputTable2[phonemeindex[loopIndex]], phonemeLength[loopIndex]);
}
loopIndex++;
continue;
}
loopIndex++;
continue;
}
if ((mem56 & 4) == 0)
{
if((mem56 & 1) == 0) {
loopIndex++;
continue;
}
R--;
if (sam_debug) fprintf(stderr,"RULE: <VOWEL> <UNVOICED PLOSIVE> - decrease vowel by 1/8th\n");
if (sam_debug) fprintf(stderr,"PRE\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
mem56 = phonemeLength[R] >> 3;
phonemeLength[R] -= mem56;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
loopIndex++;
continue;
}
if (sam_debug) fprintf(stderr,"RULE: <VOWEL> <VOICED CONSONANT> - increase vowel by 1/2 + 1\n");
if (sam_debug) fprintf(stderr,"PRE\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R-1, signInputTable1[phonemeindex[R-1]], signInputTable2[phonemeindex[R-1]], phonemeLength[R-1]);
B = phonemeLength[R-1];
phonemeLength[R-1] = (B >> 2) + B + 1;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R-1, signInputTable1[phonemeindex[R-1]], signInputTable2[phonemeindex[R-1]], phonemeLength[R-1]);
loopIndex++;
continue;
}
if((flags2[index] & 8) != 0)
{
R++;
index = phonemeindex[R];
if (index == 255)
B = 65&2; else
B = flags[index] & 2;
if (B != 0)
{
if (sam_debug) fprintf(stderr,"RULE: <NASAL> <STOP CONSONANT> - set nasal = 5, consonant = 6\n");
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R-1, signInputTable1[phonemeindex[R-1]], signInputTable2[phonemeindex[R-1]], phonemeLength[R-1]);
phonemeLength[R] = 6;
phonemeLength[R-1] = 5;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R-1, signInputTable1[phonemeindex[R-1]], signInputTable2[phonemeindex[R-1]], phonemeLength[R-1]);
}
loopIndex++;
continue;
}
if((flags[index] & 2) != 0)
{
do
{
R++;
index = phonemeindex[R];
} while(index == 0);
if (index == 255) {
if ((65 & 2) == 0) {loopIndex++; continue;}
} else if ((flags[index] & 2) == 0) {
loopIndex++;
continue;
}
if (sam_debug) fprintf(stderr,"RULE: <UNVOICED STOP CONSONANT> {optional silence} <STOP CONSONANT> - shorten both to 1/2 + 1\n");
if (sam_debug) fprintf(stderr,"PRE\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R-1, signInputTable1[phonemeindex[R-1]], signInputTable2[phonemeindex[R-1]], phonemeLength[R-1]);
int debugX = R;
phonemeLength[R] = (phonemeLength[R] >> 1) + 1;
R = loopIndex;
phonemeLength[loopIndex] = (phonemeLength[loopIndex] >> 1) + 1;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", debugX, signInputTable1[phonemeindex[debugX]], signInputTable2[phonemeindex[debugX]], phonemeLength[debugX]);
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", debugX-1, signInputTable1[phonemeindex[debugX-1]], signInputTable2[phonemeindex[debugX-1]], phonemeLength[debugX-1]);
loopIndex++;
continue;
}
if ((flags2[index] & 16) != 0)
{
index = phonemeindex[R-1];
if((flags[index] & 2) != 0) {
if (sam_debug) fprintf(stderr,"RULE: <LIQUID CONSONANT> <DIPHTONG> - decrease by 2\n");
if (sam_debug) fprintf(stderr,"PRE\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
phonemeLength[R] -= 2;
if (sam_debug) fprintf(stderr,"POST\n");
if (sam_debug) fprintf(stderr,"phoneme %d (%c%c) length %d\n", R, signInputTable1[phonemeindex[R]], signInputTable2[phonemeindex[R]], phonemeLength[R]);
}
}
loopIndex++;
continue;
}
}
void Code47503(unsigned char mem52)
{
S = 0;
if ((mem53 & 128) != 0)
{
mem53 = -mem53;
S = 128;
}
mem50 = S;
B = 0;
for(R=8; R > 0; R--)
{
int temp = mem53;
mem53 = mem53 << 1;
B = B << 1;
if (temp >= 128) B++;
if (B >= mem52)
{
B = B - mem52;
mem53++;
}
}
mem51 = B;
if ((mem50 & 128) != 0) mem53 = -mem53;
}