Source file: /~heha/basteln/Haus/Telefon/Sprachausgabe.zip/VS2008/render.c

//#include <stdio.h>
#include <string.h>
#include <stdlib.h> // abs()

#include "render.h"
#include "RenderTabs.h"

#include "debug.h"
#include "pgmspace.h"
#include "SamData.h"

unsigned char wait1 = 7;
unsigned char wait2 = 6;

extern unsigned char A, X, Y;
extern unsigned char mem44;
extern unsigned char mem47;
extern unsigned char mem49;
extern unsigned char mem39;
extern unsigned char mem50;
extern unsigned char mem51;
extern unsigned char mem53;
extern unsigned char mem56;

extern unsigned char speed;
extern unsigned char pitch;
extern int singmode;

#define phonemeIndexOutput (samdata.sam.phonemeIndexOutput)
#define stressOutput (samdata.sam.stressOutput)
#define phonemeLengthOutput (samdata.sam.phonemeLengthOutput)
#define pitches    (samdata.render.pitches)
#define frequency1 (samdata.render.frequency1)
#define frequency2 (samdata.render.frequency2)
#define frequency3 (samdata.render.frequency3)
#define amplitude1 (samdata.render.amplitude1)
#define amplitude2 (samdata.render.amplitude2)
#define amplitude3 (samdata.render.amplitude3)
#define sampledConsonantFlag (samdata.render.sampledConsonantFlag)

void AddInflection(unsigned char mem48, unsigned char phase1);
unsigned char trans(unsigned char mem39212, unsigned char mem39213);


// contains the final soundbuffer
extern int bufferpos;
//extern char *buffer;

//timetable for more accurate c64 simulation
const unsigned char timetable[5][5] PROGMEM =
{
	{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}
};

// Scheiße!!
extern void i2s_write_sample_b(unsigned char);
//extern void (*outcb)(unsigned char);

static unsigned char oldtimetableindex = 0;
static unsigned char lastAry[5];
void Output8BitAry(int index, unsigned char ary[5])
{
	int newbufferpos =  bufferpos + pgm_read_byte(&timetable[oldtimetableindex][index]);
	int bp0 = bufferpos / 50;
	int bp1 = newbufferpos / 50;
	int k=0,i;
	for (i=bp0; i<bp1; i++, k++) i2s_write_sample_b(lastAry[k]);
	memcpy(lastAry, ary, 5);
	bufferpos = newbufferpos;
	oldtimetableindex = index;
}
void 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 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];
	}
	//printf("Error reading to tables");
	return 0;
}

void 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;
	}
	//printf("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 RenderSample(unsigned char *mem66)
{
	int tempA;
	unsigned char phase1;
	// 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 = pgm_read_byte(tab48426+X); //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 = pgm_read_byte(sampleTable + mem47*256+Y); // 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&0xf)*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;



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 = pgm_read_byte(sampleTable + mem47*256+Y); //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 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 = pgm_read_byte(tab47492 + stressOutput[Y] + 1); // 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] = pgm_read_byte(&ampl1data[Y]);     // F1 amplitude
		amplitude2[X] = pgm_read_byte(&ampl2data[Y]);     // F2 amplitude
		amplitude3[X] = pgm_read_byte(&ampl3data[Y]);     // F3 amplitude
		sampledConsonantFlag[X] = pgm_read_byte(&sampledConsonantFlags[Y]);        // phoneme data for sampled consonants
		pitches[X] = pitch + phase1;      // pitch
		X++;
		phase2--;
	} while(phase2 != 0);
	mem44++;
} while(mem44 != 0);
#if (debug)
        PrintOutput(sampledConsonantFlag, frequency1, frequency2, frequency3, amplitude1, amplitude2, amplitude3, pitches);
#endif
// -------------------
//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 = pgm_read_byte(blendRank+A); //blendRank[A];
		A = pgm_read_byte(blendRank+Y); //blendRank[Y];

		// compare the rank - lower rank value is stronger
		if (A == mem56)
		{
            // same rank, so use out blend lengths from each phoneme
			phase1 = pgm_read_byte(outBlendLength+Y);//outBlendLength[Y];
			phase2 = pgm_read_byte(outBlendLength+X);//outBlendLength[X];
		} else
		if (A < mem56)
		{
            // first phoneme is stronger, so us it's blend lengths
			phase1 = pgm_read_byte(inBlendLength+X);//inBlendLength[X];
			phase2 = pgm_read_byte(outBlendLength+X);//outBlendLength[X];
		} else
		{
            // second phoneme is stronger, so use it's blend lengths
            // note the out/in are swapped
			phase1 = pgm_read_byte(outBlendLength+Y);//outBlendLength[Y];
			phase2 = pgm_read_byte(inBlendLength+Y);//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;
			mem51 = (unsigned char)abs(m53) % mem40; //abs((char)m53) % mem40;
			mem53 = (unsigned 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] = pgm_read_byte(amplitudeRescale + amplitude1[i]);//amplitudeRescale[amplitude1[i]];
		amplitude2[i] = pgm_read_byte(amplitudeRescale + amplitude2[i]);//amplitudeRescale[amplitude2[i]];
		amplitude3[i] = pgm_read_byte(amplitudeRescale + amplitude3[i]);//amplitudeRescale[amplitude3[i]];
	}

	Y = 0;
	A = pitches[0];
	mem44 = A;
	X = A;
	mem38 = A - (A>>2);     // 3/4*A ???
#if (debug)
        PrintOutput(sampledConsonantFlag, frequency1, frequency2, frequency3, amplitude1, amplitude2, amplitude3, pitches);
#endif

// 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)pgm_read_byte(&sinus[0xff & (p1>>8)]);
				signed char sp2 = (signed char)pgm_read_byte(&sinus[0xff & (p2>>8)]);
				signed char rp3 = (signed char)pgm_read_byte(&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 += ((int)frequency1[Y]) * 256 / 4; // Compromise, this becomes a shift and works well
				p2 += ((int)frequency2[Y]) * 256 / 4;
				p3 += ((int)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

}


// 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 AddInflection(unsigned char mem48, unsigned char phase1)
{
	int Atemp;
	//pos48372:
	//	mem48 = 255;
//pos48376:

    // store the location of the punctuation
	mem49 = X;
	A = X;
	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.
*/
// mouth formants (F1) 5..29
const unsigned char mouthFormants5_29[30] PROGMEM = {
                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
const unsigned char throatFormants5_29[30] PROGMEM = {
        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
const unsigned char mouthFormants48_53[6] PROGMEM = {19, 27, 21, 27, 18, 13};

        // formant 2 frequencies (throat) 48..53
const unsigned char throatFormants48_53[6] PROGMEM = {72, 39, 31, 43, 30, 34};

void SetMouthThroat(unsigned char mouth, unsigned char throat)
{
	unsigned char initialFrequency;
	unsigned char newFrequency = 0;
	//unsigned char mouth; //mem38880
	//unsigned char throat; //mem38881

	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 = pgm_read_byte(&mouthFormants5_29[pos]);
		if (initialFrequency != 0) newFrequency = trans(mouth, initialFrequency);
		freq1data[pos] = newFrequency;

		// recalculate throat frequency
		initialFrequency = pgm_read_byte(&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 = pgm_read_byte(&mouthFormants48_53[Y]);
		newFrequency = trans(mouth, initialFrequency);
		freq1data[pos] = newFrequency;

		// recalculate F2 (throat formant)
		initialFrequency = pgm_read_byte(&throatFormants48_53[Y]);
		newFrequency = trans(throat, initialFrequency);
		freq2data[pos] = newFrequency;
		Y++;
		pos++;
	}
}


//return = (mem39212*mem39213) >> 1
unsigned char 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;
}
Detected encoding: UTF-80