//void Code47574() void Render(sam_memory* sam) { unsigned char phase1 = 0; //mem43 unsigned char phase2; unsigned char phase3; unsigned char mem38; unsigned char mem40; unsigned char speedcounter; //mem45 unsigned char mem47; unsigned char mem48; unsigned char mem49; unsigned char mem50; unsigned char mem51; unsigned char mem53; unsigned char mem56; unsigned char mem44 = 0; int i; if (sam->common.phoneme_output[0].index == PHONEME_END) return; //exit if no data unsigned char A = 0; unsigned char X = 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. do { // get the index unsigned char Y = mem44; // get the phoneme at the index A = sam->common.phoneme_output[mem44].index; mem56 = A; // if terminal phoneme, exit the loop if (A == PHONEME_END) break; // period phoneme *. if (A == 1) { // add rising inflection A = 1; mem48 = 1; //goto pos48376; AddInflection(sam, mem48, phase1, X); } /* if (A == 2) goto pos48372; */ // question mark phoneme? if (A == 2) { // create falling inflection mem48 = 255; AddInflection(sam, mem48, phase1, X); } // pos47615: // get the stress amount (more stress = higher pitch) phase1 = tab47492[sam->common.phoneme_output[Y].stress + 1]; // get number of frames to write phase2 = sam->common.phoneme_output[Y].length; unsigned char pitch = sam->common.phoneme_output[Y].pitch; Y = mem56; // copy from the source to the frames list do { sam->render.freq_amp[X].freq1 = get_freq1(Y, sam->common.mouth); // F1 frequency sam->render.freq_amp[X].freq2 = get_freq2(Y, sam->common.throat); // F2 frequency sam->render.freq_amp[X].freq3 = freq3data[Y]; // F3 frequency sam->render.freq_amp[X].amp1 = ampl1data[Y]; // F1 amplitude sam->render.freq_amp[X].amp2 = ampl2data[Y]; // F2 amplitude sam->render.freq_amp[X].amp3 = ampl3data[Y]; // F3 amplitude sam->render.flags[X] = sampledConsonantFlags[Y]; // phoneme data for sampled consonants sam->render.pitch[X] = pitch + phase1; // pitch X++; phase2--; } while(phase2 != 0); mem44++; } while(mem44 != OUTPUT_PHONEMES); // ------------------- //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 unsigned char Y = sam->common.phoneme_output[X].index; A = sam->common.phoneme_output[X+1].index; X++; // exit loop at end token if (A == PHONEME_END) 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 + sam->common.phoneme_output[mem44].length; // 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 = sam->common.phoneme_output[mem44].length >> 1; // half the width of the next phoneme mem37 = sam->common.phoneme_output[mem44+1].length >> 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(sam, mem47, mem37); // value at center of next phoneme - end interpolation value //A = mem[address]; Y = mem36; // start index of interpolation mem53 = A - Read(sam, mem47, mem36); // value to center of current phoneme } else { // value to interpolate to A = Read(sam, mem47, speedcounter); // position to start interpolation from Y = phase3; // value to interpolate from mem53 = A - Read(sam, mem47, phase3); } // calculate change per frame mem50 = (((signed char)(mem53) < 0) ? 128 : 0); mem51 = abs((signed char)mem53) % mem40; mem53 = (unsigned char)((signed char)(mem53) / 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(sam, 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(sam, 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
//void Code47574() void Render() { unsigned char phase1 = 0; //mem43 unsigned char phase2; unsigned char phase3; unsigned char mem66; unsigned char mem38; unsigned char mem40; unsigned char speedcounter; //mem45 unsigned char mem48; int i; int carry; 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 each // phoeneme. This transition is spread between the ending frames // of the old phoneme (outBlendLength), and the beginning frames // of the new phoneme (inBlendLength). // // To determine how many frames to use, the two phonemes are // compared using the blendRank[] table. The phoneme with the // smaller score is used. 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 around! // outBlendFrames = inBlendLength[phoneme2] // inBlendFrames = outBlendLength[phoneme2] // // Blend lengths can't be less than zero. // // 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. 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 mem50 = (((char)(mem53) < 0) ? 128 : 0); mem51 = abs((char)mem53) % mem40; mem53 = (unsigned char)((char)(mem53) / 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