tom dunigan
/
tts
text-to-speech through DAC to audio amp/speaker
text-to-speech TTS
- This program was based on modifying the Arduino/Teensy TTS library https://github.com/manitou48/TTS
- The audio is generated with the ARM's DAC pin.
- TTS.h selects DAC pin based on MBED board. Only tested on K64F
- Teensy discussions https://forum.pjrc.com/threads/44587-TTS-(Text-to-Speech)-Library-Port
Revision 3:d12c34704b6d, committed 2017-06-24
- Comitter:
- manitou
- Date:
- Sat Jun 24 19:41:42 2017 +0000
- Parent:
- 2:eceeac07154b
- Commit message:
- format/indent
Changed in this revision
TTS.cpp | Show annotated file Show diff for this revision Revisions of this file |
diff -r eceeac07154b -r d12c34704b6d TTS.cpp --- a/TTS.cpp Sat Jun 24 14:10:48 2017 +0000 +++ b/TTS.cpp Sat Jun 24 19:41:42 2017 +0000 @@ -1,5 +1,5 @@ -/** - * Text To Speech synthesis library +/** + * Text To Speech synthesis library * Copyright (c) 2008 Clive Webster. All rights reserved. * * Nov. 29th 2009 - Modified to work with Arduino by Gabriel Petrut: @@ -7,7 +7,7 @@ * output on digital pin 10. The output signal needs to be fed * to an RC filter then through an amplifier to the speaker. * http://www.tehnorama.ro/minieric-modulul-de-control-si-sinteza-vocala/ - * + * * Modified to allow use of different PWM pins by Stephen Crane. * Modified for Timer5 on Arduino Mega2560 by Peter Dambrowsky. */ @@ -37,16 +37,16 @@ static int copyToken(char token, char *dest, int x, const VOCAB * vocab) { for (unsigned int ph = 0; ph < numVocab; ph++) { - const char *txt = (const char *) pgm_read_word(&vocab[ph].txt); - if (pgm_read_byte(&txt[0]) == token && pgm_read_byte(&txt[1]) == 0) { - const char *src = - (const char *) pgm_read_word(&vocab[ph].phoneme); - while (pgm_read_byte(src)) { - dest[x++] = pgm_read_byte(src); - src++; + const char *txt = (const char *) pgm_read_word(&vocab[ph].txt); + if (pgm_read_byte(&txt[0]) == token && pgm_read_byte(&txt[1]) == 0) { + const char *src = + (const char *) pgm_read_word(&vocab[ph].phoneme); + while (pgm_read_byte(src)) { + dest[x++] = pgm_read_byte(src); + src++; + } + break; } - break; - } } return x; } @@ -54,7 +54,7 @@ static byte whitespace(char c) { return (c == 0 || c == ' ' || c == ',' || c == '.' || c == '?' - || c == '\'' || c == '!' || c == ':' || c == '/'); + || c == '\'' || c == '!' || c == ':' || c == '/'); } /** @@ -70,104 +70,104 @@ int inIndex = -1; // Starts at -1 so that a leading space is assumed while (inIndex == -1 || src[inIndex]) { // until end of text - int maxMatch = 0; // Max chars matched on input text - int numOut = 0; // Number of characters copied to output stream for the best match - boolean endsInWhiteSpace = FALSE; - int maxWildcardPos = 0; + int maxMatch = 0; // Max chars matched on input text + int numOut = 0; // Number of characters copied to output stream for the best match + boolean endsInWhiteSpace = FALSE; + int maxWildcardPos = 0; - // Get next phoneme, P2 - for (unsigned int ph = 0; ph < numVocab; ph++) { - int y, x; - char wildcard = 0; // modifier - int wildcardInPos = 0; - boolean hasWhiteSpace = FALSE; - const char *text = - (const char *) pgm_read_word(&vocab[ph].txt); - const char *phon = - (const char *) pgm_read_word(&vocab[ph].phoneme); + // Get next phoneme, P2 + for (unsigned int ph = 0; ph < numVocab; ph++) { + int y, x; + char wildcard = 0; // modifier + int wildcardInPos = 0; + boolean hasWhiteSpace = FALSE; + const char *text = + (const char *) pgm_read_word(&vocab[ph].txt); + const char *phon = + (const char *) pgm_read_word(&vocab[ph].phoneme); - for (y = 0;; y++) { - char nextVocabChar = pgm_read_byte(&text[y]); - char nextCharIn = - (y + inIndex == -1) ? ' ' : src[y + inIndex]; - if (nextCharIn >= 'a' && nextCharIn <= 'z') - nextCharIn = nextCharIn - 'a' + 'A'; + for (y = 0;; y++) { + char nextVocabChar = pgm_read_byte(&text[y]); + char nextCharIn = + (y + inIndex == -1) ? ' ' : src[y + inIndex]; + if (nextCharIn >= 'a' && nextCharIn <= 'z') + nextCharIn = nextCharIn - 'a' + 'A'; - if (nextVocabChar == '#' && nextCharIn >= 'A' - && nextCharIn <= 'Z') { - wildcard = nextCharIn; // The character equivalent to the '#' - wildcardInPos = y; - continue; - } + if (nextVocabChar == '#' && nextCharIn >= 'A' + && nextCharIn <= 'Z') { + wildcard = nextCharIn; // The character equivalent to the '#' + wildcardInPos = y; + continue; + } - if (nextVocabChar == '_') { - // try to match against a white space - hasWhiteSpace = TRUE; - if (whitespace(nextCharIn)) - continue; - y--; - break; - } - // check for end of either string - if (nextVocabChar == 0 || nextCharIn == 0) - break; + if (nextVocabChar == '_') { + // try to match against a white space + hasWhiteSpace = TRUE; + if (whitespace(nextCharIn)) + continue; + y--; + break; + } + // check for end of either string + if (nextVocabChar == 0 || nextCharIn == 0) + break; - if (nextVocabChar != nextCharIn) - break; - } + if (nextVocabChar != nextCharIn) + break; + } - // See if its the longest complete match so far - if (y <= maxMatch || pgm_read_byte(&text[y])) - continue; + // See if its the longest complete match so far + if (y <= maxMatch || pgm_read_byte(&text[y])) + continue; - // This is the longest complete match - maxMatch = y; - maxWildcardPos = 0; - x = outIndex; // offset into phoneme return data + // This is the longest complete match + maxMatch = y; + maxWildcardPos = 0; + x = outIndex; // offset into phoneme return data - // Copy the matching phrase changing any '#' to the phoneme for the wildcard - for (y = 0;; y++) { - char c = pgm_read_byte(&phon[y]); - if (c == 0) - break; - if (c == '#') { - if (pgm_read_byte(&phon[y + 1]) == 0) { - // replacement ends in wildcard - maxWildcardPos = wildcardInPos; - } else { - x = copyToken(wildcard, dest, x, vocab); // Copy the phonemes for the wildcard character + // Copy the matching phrase changing any '#' to the phoneme for the wildcard + for (y = 0;; y++) { + char c = pgm_read_byte(&phon[y]); + if (c == 0) + break; + if (c == '#') { + if (pgm_read_byte(&phon[y + 1]) == 0) { + // replacement ends in wildcard + maxWildcardPos = wildcardInPos; + } else { + x = copyToken(wildcard, dest, x, vocab); // Copy the phonemes for the wildcard character + } + } else { + dest[x++] = c; + } } - } else { - dest[x++] = c; - } + dest[x] = 0; + endsInWhiteSpace = hasWhiteSpace; + + // 14 + numOut = x - outIndex; // The number of bytes added } - dest[x] = 0; - endsInWhiteSpace = hasWhiteSpace; + // 15 - end of vocab table - // 14 - numOut = x - outIndex; // The number of bytes added - } - // 15 - end of vocab table - - // 16 - if (endsInWhiteSpace) - maxMatch--; + // 16 + if (endsInWhiteSpace) + maxMatch--; - // 17 - if (maxMatch == 0) { - //loggerP(PSTR("Mistake in SAY, no token for ")); - //logger(&src[inIndex]); - //loggerCRLF(); - return 0; - } - // 20 - outIndex += numOut; - if (outIndex > 128 - 16) { - //loggerP(PSTR("Mistake in SAY, text too long\n")); - return 0; - } - // 21 - inIndex += (maxWildcardPos > 0) ? maxWildcardPos : maxMatch; + // 17 + if (maxMatch == 0) { + //loggerP(PSTR("Mistake in SAY, no token for ")); + //logger(&src[inIndex]); + //loggerCRLF(); + return 0; + } + // 20 + outIndex += numOut; + if (outIndex > 128 - 16) { + //loggerP(PSTR("Mistake in SAY, text too long\n")); + return 0; + } + // 21 + inIndex += (maxWildcardPos > 0) ? maxWildcardPos : maxMatch; } return 1; } @@ -186,106 +186,106 @@ unsigned int L80 = 16; while (*textp) { - // P20: Get next phoneme - boolean anyMatch = FALSE; - int longestMatch = 0; - int numOut = 0; // The number of bytes copied to the output for the longest match + // P20: Get next phoneme + boolean anyMatch = FALSE; + int longestMatch = 0; + int numOut = 0; // The number of bytes copied to the output for the longest match - // Get next phoneme, P2 - for (unsigned int ph = 0; ph < numPhoneme; ph++) { - int numChars; + // Get next phoneme, P2 + for (unsigned int ph = 0; ph < numPhoneme; ph++) { + int numChars; - // Locate start of next phoneme - const char *ph_text = - (const char *) pgm_read_word(&phoneme[ph].txt); + // Locate start of next phoneme + const char *ph_text = + (const char *) pgm_read_word(&phoneme[ph].txt); - // Set 'numChars' to the number of characters - // that we match against this phoneme - for (numChars = 0; textp[numChars]; numChars++) { + // Set 'numChars' to the number of characters + // that we match against this phoneme + for (numChars = 0; textp[numChars]; numChars++) { - // get next input character and make lower case - char nextChar = textp[numChars]; - if (nextChar >= 'A' && nextChar <= 'Z') - nextChar = nextChar - 'A' + 'a'; + // get next input character and make lower case + char nextChar = textp[numChars]; + if (nextChar >= 'A' && nextChar <= 'Z') + nextChar = nextChar - 'A' + 'a'; - if (nextChar != pgm_read_byte(&ph_text[numChars])) - break; - } + if (nextChar != pgm_read_byte(&ph_text[numChars])) + break; + } - // if not the longest match so far then ignore - if (numChars <= longestMatch) - continue; + // if not the longest match so far then ignore + if (numChars <= longestMatch) + continue; - // partial phoneme match - if (pgm_read_byte(&ph_text[numChars])) - continue; + // partial phoneme match + if (pgm_read_byte(&ph_text[numChars])) + continue; - // P7: we have matched the whole phoneme - longestMatch = numChars; + // P7: we have matched the whole phoneme + longestMatch = numChars; - // Copy phoneme data to 'phonemes' - const char *ph_ph = - (const char *) pgm_read_word(&phoneme[ph].phoneme); - for (numOut = 0; pgm_read_byte(&ph_ph[numOut]); numOut++) - phonemes[phonemeOut + numOut] = - pgm_read_byte(&ph_ph[numOut]); + // Copy phoneme data to 'phonemes' + const char *ph_ph = + (const char *) pgm_read_word(&phoneme[ph].phoneme); + for (numOut = 0; pgm_read_byte(&ph_ph[numOut]); numOut++) + phonemes[phonemeOut + numOut] = + pgm_read_byte(&ph_ph[numOut]); - L81 = pgm_read_byte(&phoneme[ph].attenuate) + '0'; - anyMatch = TRUE; // phoneme match found + L81 = pgm_read_byte(&phoneme[ph].attenuate) + '0'; + anyMatch = TRUE; // phoneme match found - modifier[modifierOut] = -1; - modifier[modifierOut + 1] = 0; + modifier[modifierOut] = -1; + modifier[modifierOut + 1] = 0; - // Get char from text after the phoneme and test if it is a numeric - if (textp[longestMatch] >= '0' && textp[longestMatch] <= '9') { - // Pitch change requested - modifier[modifierOut] = - pgm_read_byte(&PitchesP[textp[longestMatch] - '1']); - modifier[modifierOut + 1] = L81; - longestMatch++; - } - // P10 - if (L81 != '0' && L81 != L80 && modifier[modifierOut] >= 0) { - modifier[modifierOut - 2] = modifier[modifierOut]; - modifier[modifierOut - 1] = '0'; - continue; - } - // P11 - if ((textp[longestMatch - 1] | 0x20) == 0x20) { - // end of input string or a space - modifier[modifierOut] = - (modifierOut == 0) ? 16 : modifier[modifierOut - 2]; - } - } // next phoneme + // Get char from text after the phoneme and test if it is a numeric + if (textp[longestMatch] >= '0' && textp[longestMatch] <= '9') { + // Pitch change requested + modifier[modifierOut] = + pgm_read_byte(&PitchesP[textp[longestMatch] - '1']); + modifier[modifierOut + 1] = L81; + longestMatch++; + } + // P10 + if (L81 != '0' && L81 != L80 && modifier[modifierOut] >= 0) { + modifier[modifierOut - 2] = modifier[modifierOut]; + modifier[modifierOut - 1] = '0'; + continue; + } + // P11 + if ((textp[longestMatch - 1] | 0x20) == 0x20) { + // end of input string or a space + modifier[modifierOut] = + (modifierOut == 0) ? 16 : modifier[modifierOut - 2]; + } + } // next phoneme - // p13 - L80 = L81; - if (longestMatch == 0 && !anyMatch) { - //loggerP(PSTR("Mistake in speech at ")); - //logger(textp); - //loggerCRLF(); - return 0; - } - // Move over the bytes we have copied to the output - phonemeOut += numOut; + // p13 + L80 = L81; + if (longestMatch == 0 && !anyMatch) { + //loggerP(PSTR("Mistake in speech at ")); + //logger(textp); + //loggerCRLF(); + return 0; + } + // Move over the bytes we have copied to the output + phonemeOut += numOut; - if (phonemeOut > sizeof(phonemes) - 16) { - //loggerP(PSTR("Line too long\n")); - return 0; - } - // P16 + if (phonemeOut > sizeof(phonemes) - 16) { + //loggerP(PSTR("Line too long\n")); + return 0; + } + // P16 - // Copy the modifier setting to each sound data element for this phoneme - if (numOut > 2) - for (int count = 0; count != numOut; count += 2) { - modifier[modifierOut + count + 2] = - modifier[modifierOut + count]; - modifier[modifierOut + count + 3] = 0; - } - modifierOut += numOut; + // Copy the modifier setting to each sound data element for this phoneme + if (numOut > 2) + for (int count = 0; count != numOut; count += 2) { + modifier[modifierOut + count + 2] = + modifier[modifierOut + count]; + modifier[modifierOut + count + 3] = 0; + } + modifierOut += numOut; - //p21 - textp += longestMatch; + //p21 + textp += longestMatch; } phonemes[phonemeOut++] = 'z'; @@ -294,11 +294,11 @@ phonemes[phonemeOut++] = 'z'; while (phonemeOut < sizeof(phonemes)) - phonemes[phonemeOut++] = 0; + phonemes[phonemeOut++] = 0; while (modifierOut < sizeof(modifier)) { - modifier[modifierOut++] = -1; - modifier[modifierOut++] = 0; + modifier[modifierOut++] = -1; + modifier[modifierOut++] = 0; } return 1; @@ -327,13 +327,13 @@ byte tmp = (seed0 & 0x48) + 0x38; seed0 <<= 1; if (seed1 & 0x80) - seed0++; + seed0++; seed1 <<= 1; if (seed2 & 0x80) - seed1++; + seed1++; seed2 <<= 1; if (tmp & 0x40) - seed2++; + seed2++; return seed0; } @@ -349,7 +349,7 @@ //https://sites.google.com/site/qeewiki/books/avr-guide/pwm-on-the-atmega328 static void soundOn(void) { - // dac.write(0); + // dac.write(0); // initialise random number seed seed0 = 0xecu; @@ -359,34 +359,34 @@ // Logarithmic scale //static const int16_t PROGMEM Volume[8] = - //{ 0, PWM_TOP * 0.01, PWM_TOP * 0.02, PWM_TOP * 0.03, PWM_TOP * 0.06, +//{ 0, PWM_TOP * 0.01, PWM_TOP * 0.02, PWM_TOP * 0.03, PWM_TOP * 0.06, //PWM_TOP * 0.12, PWM_TOP * 0.25, PWM_TOP * 0.5 }; // Linear scale -static const int16_t PROGMEM Volume[8] = - { 0, (uint16_t)(PWM_TOP * 0.07), (uint16_t)(PWM_TOP * 0.14), (uint16_t)(PWM_TOP * 0.21), (uint16_t)(PWM_TOP * 0.29), +static const int16_t PROGMEM Volume[8] = { + 0, (uint16_t)(PWM_TOP * 0.07), (uint16_t)(PWM_TOP * 0.14), (uint16_t)(PWM_TOP * 0.21), (uint16_t)(PWM_TOP * 0.29), (uint16_t)(PWM_TOP * 0.36), (uint16_t)(PWM_TOP * 0.43), (uint16_t)(PWM_TOP * 0.5) }; static void sound(byte b) { - // Update PWM volume + // Update PWM volume b = (b & 15); dac.write(0.5*b/16.); } static byte playTone(byte soundNum, byte soundPos, char pitch1, - char pitch2, byte count, byte volume) + char pitch2, byte count, byte volume) { const byte *soundData = &SoundData[soundNum * 0x40]; while (count-- > 0) { - byte s = pgm_read_byte(&soundData[soundPos & 0x3fu]); - sound((byte) (s & volume)); - pause(pitch1); - sound((byte) ((s >> 4) & volume)); - pause(pitch2); + byte s = pgm_read_byte(&soundData[soundPos & 0x3fu]); + sound((byte) (s & volume)); + pause(pitch1); + sound((byte) ((s >> 4) & volume)); + pause(pitch2); - soundPos++; + soundPos++; } return soundPos & 0x3fu; } @@ -394,7 +394,7 @@ static void play(byte duration, byte soundNumber) { while (duration--) - playTone(soundNumber, random2(), 7, 7, 10, 15); + playTone(soundNumber, random2(), 7, 7, 10, 15); } /****************************************************************************** @@ -420,8 +420,8 @@ void TTS::sayPhonemes(const char *textp) { byte phonemeIn, // offset into text - byte2, modifierIn, // offset into stuff in modifier - punctuationPitchDelta; // change in pitch due to fullstop or question mark + byte2, modifierIn, // offset into stuff in modifier + punctuationPitchDelta; // change in pitch due to fullstop or question mark int8_t byte1; char phoneme; const SOUND_INDEX *soundIndex; @@ -434,184 +434,184 @@ byte sound1Duration; // the duration for sound 1 if (phonemesToData(textp, s_phonemes)) { - // phonemes has list of sound bytes - soundOn(); + // phonemes has list of sound bytes + soundOn(); - // _630C - byte1 = 0; - punctuationPitchDelta = 0; + // _630C + byte1 = 0; + punctuationPitchDelta = 0; - // Q19 - for (phonemeIn = 0, modifierIn = 0; phonemes[phonemeIn]; - phonemeIn += 2, modifierIn += 2) { - byte duration; // duration from text line - byte SoundPos; // offset into sound data - byte fadeSpeed = 0; + // Q19 + for (phonemeIn = 0, modifierIn = 0; phonemes[phonemeIn]; + phonemeIn += 2, modifierIn += 2) { + byte duration; // duration from text line + byte SoundPos; // offset into sound data + byte fadeSpeed = 0; - phoneme = phonemes[phonemeIn]; - if (phoneme == 'z') { - delay2(15); - continue; - } else if (phoneme == '#') { - continue; - } else { + phoneme = phonemes[phonemeIn]; + if (phoneme == 'z') { + delay2(15); + continue; + } else if (phoneme == '#') { + continue; + } else { - // Collect info on sound 1 - soundIndex = &SoundIndex[phoneme - 'A']; - sound1Num = pgm_read_byte(&soundIndex->SoundNumber); - byte1 = pgm_read_byte(&soundIndex->byte1); - byte2 = pgm_read_byte(&soundIndex->byte2); + // Collect info on sound 1 + soundIndex = &SoundIndex[phoneme - 'A']; + sound1Num = pgm_read_byte(&soundIndex->SoundNumber); + byte1 = pgm_read_byte(&soundIndex->byte1); + byte2 = pgm_read_byte(&soundIndex->byte2); - duration = phonemes[phonemeIn + 1] - '0'; // Get duration from the input line - if (duration != 1) - duration <<= 1; + duration = phonemes[phonemeIn + 1] - '0'; // Get duration from the input line + if (duration != 1) + duration <<= 1; - duration += 6; // scaled duration from the input line (at least 6) - sound2Stop = 0x40 >> 1; + duration += 6; // scaled duration from the input line (at least 6) + sound2Stop = 0x40 >> 1; - pitch1 = modifier[modifierIn]; - if (modifier[modifierIn + 1] == 0 || pitch1 == -1) { - pitch1 = 10; - duration -= 6; - } else if (modifier[modifierIn + 1] == '0' - || duration == 6) { - duration -= 6; - } - // q8 - pitch2 = modifier[modifierIn + 2]; - if (modifier[modifierIn + 3] == 0 || pitch2 == -1) - pitch2 = 10; + pitch1 = modifier[modifierIn]; + if (modifier[modifierIn + 1] == 0 || pitch1 == -1) { + pitch1 = 10; + duration -= 6; + } else if (modifier[modifierIn + 1] == '0' + || duration == 6) { + duration -= 6; + } + // q8 + pitch2 = modifier[modifierIn + 2]; + if (modifier[modifierIn + 3] == 0 || pitch2 == -1) + pitch2 = 10; - // q10 - if (byte1 < 0) { - sound1Num = 0; - random2(); - sound2Stop = (0x40 >> 1) + 2; - } else { - // is positive - if (byte1 == 2) { - // 64A4 - // Make a white noise sound ! - byte volume = (duration == 6) ? 15 : 1; // volume mask - for (duration <<= 2; duration > 0; duration--) { - playTone(sound1Num, random2(), 8, 12, 11, - volume); - // Increase the volume - if (++volume == 16) - volume = 15; // full volume from now on - } - continue; + // q10 + if (byte1 < 0) { + sound1Num = 0; + random2(); + sound2Stop = (0x40 >> 1) + 2; + } else { + // is positive + if (byte1 == 2) { + // 64A4 + // Make a white noise sound ! + byte volume = (duration == 6) ? 15 : 1; // volume mask + for (duration <<= 2; duration > 0; duration--) { + playTone(sound1Num, random2(), 8, 12, 11, + volume); + // Increase the volume + if (++volume == 16) + volume = 15; // full volume from now on + } + continue; - } else { - // q11 - if (byte1) - delay2(25); + } else { + // q11 + if (byte1) + delay2(25); + } + } } - } - } - // 6186 - pitch1 += defaultPitch + punctuationPitchDelta; - if (pitch1 < 1) - pitch1 = 1; + // 6186 + pitch1 += defaultPitch + punctuationPitchDelta; + if (pitch1 < 1) + pitch1 = 1; - pitch2 += defaultPitch + punctuationPitchDelta; - if (pitch2 < 1) - pitch2 = 1; + pitch2 += defaultPitch + punctuationPitchDelta; + if (pitch2 < 1) + pitch2 = 1; - // get next phoneme - phoneme = phonemes[phonemeIn + 2]; + // get next phoneme + phoneme = phonemes[phonemeIn + 2]; - if (phoneme == 0 || phoneme == 'z') { - if (duration == 1) - delay2(60); - phoneme = 'a'; // change to a pause - } else { - // s6 - if (byte2 != 1) - byte2 = - (byte2 + - pgm_read_byte(&SoundIndex[phoneme - 'A'].byte2)) - >> 1; + if (phoneme == 0 || phoneme == 'z') { + if (duration == 1) + delay2(60); + phoneme = 'a'; // change to a pause + } else { + // s6 + if (byte2 != 1) + byte2 = + (byte2 + + pgm_read_byte(&SoundIndex[phoneme - 'A'].byte2)) + >> 1; - if (byte1 < 0 - || pgm_read_byte(&SoundIndex[phoneme - 'A'].byte1)) - phoneme = 'a'; // change to a pause - } + if (byte1 < 0 + || pgm_read_byte(&SoundIndex[phoneme - 'A'].byte1)) + phoneme = 'a'; // change to a pause + } - // S10 - sound2Num = - pgm_read_byte(&SoundIndex[phoneme - 'A'].SoundNumber); + // S10 + sound2Num = + pgm_read_byte(&SoundIndex[phoneme - 'A'].SoundNumber); - sound1Duration = 0x80; // play half of sound 1 - if (sound2Num == sound1Num) - byte2 = duration; + sound1Duration = 0x80; // play half of sound 1 + if (sound2Num == sound1Num) + byte2 = duration; - // S11 - if ((byte2 >> 1) == 0) { - sound1Duration = 0xff; // play all of sound 1 - } else { - // The fade speed between the two sounds - fadeSpeed = (sound1Duration + (byte2 >> 1)) / byte2; + // S11 + if ((byte2 >> 1) == 0) { + sound1Duration = 0xff; // play all of sound 1 + } else { + // The fade speed between the two sounds + fadeSpeed = (sound1Duration + (byte2 >> 1)) / byte2; - if (duration == 1) { - sound2Stop = 0x40; // dont play sound2 - sound1Duration = 0xff; // play all of sound 1 - pitch1 = 12; - } - } + if (duration == 1) { + sound2Stop = 0x40; // dont play sound2 + sound1Duration = 0xff; // play all of sound 1 + pitch1 = 12; + } + } - SoundPos = 0; - do { - byte sound1Stop = (sound1Duration >> 2) & 0x3fu; - byte sound1End = sound1Stop; - if (sound2Stop < sound1End) sound1End = sound2Stop; // min + SoundPos = 0; + do { + byte sound1Stop = (sound1Duration >> 2) & 0x3fu; + byte sound1End = sound1Stop; + if (sound2Stop < sound1End) sound1End = sound2Stop; // min - if (sound1Stop) - SoundPos = - playTone(sound1Num, SoundPos, pitch1, pitch1, - sound1End, 15); + if (sound1Stop) + SoundPos = + playTone(sound1Num, SoundPos, pitch1, pitch1, + sound1End, 15); - // s18 - if (sound2Stop != 0x40) { - SoundPos = - playTone(sound2Num, SoundPos, pitch2, pitch2, - (byte) (sound2Stop - sound1End), 15); - } - // s23 - if (sound1Duration != 0xff && duration < byte2) { - // Fade sound1 out - sound1Duration -= fadeSpeed; - if (sound1Duration >= (byte) 0xC8) - sound1Duration = 0; // stop playing sound 1 - } - // Call any additional sound - if (byte1 == -1) - play(3, 30); // make an 'f' sound - else if (byte1 == -2) - play(3, 29); // make an 's' sound - else if (byte1 == -3) - play(3, 33); // make a 'th' sound - else if (byte1 == -4) - play(3, 27); // make a 'sh' sound + // s18 + if (sound2Stop != 0x40) { + SoundPos = + playTone(sound2Num, SoundPos, pitch2, pitch2, + (byte) (sound2Stop - sound1End), 15); + } + // s23 + if (sound1Duration != 0xff && duration < byte2) { + // Fade sound1 out + sound1Duration -= fadeSpeed; + if (sound1Duration >= (byte) 0xC8) + sound1Duration = 0; // stop playing sound 1 + } + // Call any additional sound + if (byte1 == -1) + play(3, 30); // make an 'f' sound + else if (byte1 == -2) + play(3, 29); // make an 's' sound + else if (byte1 == -3) + play(3, 33); // make a 'th' sound + else if (byte1 == -4) + play(3, 27); // make a 'sh' sound - } while (--duration); + } while (--duration); - // Scan ahead to find a '.' or a '?' as this will change the pitch - punctuationPitchDelta = 0; - for (i = 6; i > 0; i--) { - char next = phonemes[phonemeIn + (i * 2)]; - if (next == 'i') - // found a full stop - punctuationPitchDelta = 6 - i; // Lower the pitch - else if (next == 'h') - // found a question mark - punctuationPitchDelta = i - 6; // Raise the pitch - } + // Scan ahead to find a '.' or a '?' as this will change the pitch + punctuationPitchDelta = 0; + for (i = 6; i > 0; i--) { + char next = phonemes[phonemeIn + (i * 2)]; + if (next == 'i') + // found a full stop + punctuationPitchDelta = 6 - i; // Lower the pitch + else if (next == 'h') + // found a question mark + punctuationPitchDelta = i - 6; // Raise the pitch + } - if (byte1 == 1) - delay2(25); - } // next phoneme + if (byte1 == 1) + delay2(25); + } // next phoneme } soundOff(); } @@ -622,7 +622,7 @@ void TTS::sayText(const char *original) { unsigned int i; - if (textToPhonemes(original, s_vocab, g_text)) { - sayPhonemes(g_text); + if (textToPhonemes(original, s_vocab, g_text)) { + sayPhonemes(g_text); } } \ No newline at end of file