Talkie speech library

Status
Not open for further replies.
Wanna have a "Teensyier" qBlink(); ?
Code:
#define qBlink() {GPIOC_PTOR=32;}
:)

You are my hero FrankB - does that work on LC as well?

Update pending . . . changing the return of .active() from bool to count of number of sounds to play until silence, where ZERO means silent now.
 
Updated the PULL requested - includes indicated change to .active() return value.

Modified sample from Adrian (using Prop Shield) to demonstrate usage of .say() and all added methods of "Talkie voice":View attachment SayQAcornAdrian.ino Also uses FrankB faster qBlink()!

Edits to Talkie.cpp and .h and keywords.txt :: Removed the delay(25) from .say using .sayQ

Called it sayQ() because I added a 24 sound queue managed in the code so not one but 25 sounds can be pushed into a queue for playing sequentially without user attention or delay.

.active() - is **false** on silence, else **returns count** of sounds yet to play
.sayQ() - returns the space left in queue
.sayQ(0) empties the que and stops audio out
.say(0) empties the que and stops audio out
.say() is otherwise 'unchanged' - it will block

Added example of all methods: SayQAcorn.ino
Core Talkie code unchanged, except for cascaded timer to update synthesis data
 
groovy...Thanks so much for doing this ....I guess you got a surprise when I left out the digital pin write for the prop board from my example (im using a usb interface and a high quality standalone headphone amp) ... I'm playing around with your voltmeter example. I like it a lot. I think I might index the acorn samples completely..... its fun using a string of numbers to make the lc talk. and it could be handy for receiving numbers from the serial input, counting them, putting them in an array and sending them to 'sendQ' .... I need to learn a bit more about buffers and things. thanks again.
 
I've modified your first voltmeter example ... I used indexing and a data array ... The way your example calls a function within a function is most instructive I would never have worked that out on my own in 999999 years ... very clever technique. Anyway, my rewrite seems to work without calling a blocking 'say' to stage the audio, and the indexing appears to save a bit of memory... its so much fun ... I'm going to get it to count beats "1 and 2 and 3 and 4" from my sequencer clock, just for giggles. I wrote one song in 19 / 8 time a couple of years ago ... might be more of a challenge.... Maybe it can tell me the current volume or pan setting... or maybe my current midi channel... oh joy.

Code:
#define VOLTMETER
#include <Talkie.h>

#ifdef VOLTMETER

/*    0*/const uint8_t NOTHING[]    PROGMEM = {0};
/*    1*/const uint8_t spONE[]      PROGMEM = {0x66, 0x4E, 0xA8, 0x7A, 0x8D, 0xED, 0xC4, 0xB5, 0xCD, 0x89, 0xD4, 0xBC, 0xA2, 0xDB, 0xD1, 0x27, 0xBE, 0x33, 0x4C, 0xD9, 0x4F, 0x9B, 0x4D, 0x57, 0x8A, 0x76, 0xBE, 0xF5, 0xA9, 0xAA, 0x2E, 0x4F, 0xD5, 0xCD, 0xB7, 0xD9, 0x43, 0x5B, 0x87, 0x13, 0x4C, 0x0D, 0xA7, 0x75, 0xAB, 0x7B, 0x3E, 0xE3, 0x19, 0x6F, 0x7F, 0xA7, 0xA7, 0xF9, 0xD0, 0x30, 0x5B, 0x1D, 0x9E, 0x9A, 0x34, 0x44, 0xBC, 0xB6, 0x7D, 0xFE, 0x1F};
/*    2*/const uint8_t spTWO[]      PROGMEM = {0x06, 0xB8, 0x59, 0x34, 0x00, 0x27, 0xD6, 0x38, 0x60, 0x58, 0xD3, 0x91, 0x55, 0x2D, 0xAA, 0x65, 0x9D, 0x4F, 0xD1, 0xB8, 0x39, 0x17, 0x67, 0xBF, 0xC5, 0xAE, 0x5A, 0x1D, 0xB5, 0x7A, 0x06, 0xF6, 0xA9, 0x7D, 0x9D, 0xD2, 0x6C, 0x55, 0xA5, 0x26, 0x75, 0xC9, 0x9B, 0xDF, 0xFC, 0x6E, 0x0E, 0x63, 0x3A, 0x34, 0x70, 0xAF, 0x3E, 0xFF, 0x1F};
/*    3*/const uint8_t spTHREE[]    PROGMEM = {0x0C, 0xE8, 0x2E, 0x94, 0x01, 0x4D, 0xBA, 0x4A, 0x40, 0x03, 0x16, 0x68, 0x69, 0x36, 0x1C, 0xE9, 0xBA, 0xB8, 0xE5, 0x39, 0x70, 0x72, 0x84, 0xDB, 0x51, 0xA4, 0xA8, 0x4E, 0xA3, 0xC9, 0x77, 0xB1, 0xCA, 0xD6, 0x52, 0xA8, 0x71, 0xED, 0x2A, 0x7B, 0x4B, 0xA6, 0xE0, 0x37, 0xB7, 0x5A, 0xDD, 0x48, 0x8E, 0x94, 0xF1, 0x64, 0xCE, 0x6D, 0x19, 0x55, 0x91, 0xBC, 0x6E, 0xD7, 0xAD, 0x1E, 0xF5, 0xAA, 0x77, 0x7A, 0xC6, 0x70, 0x22, 0xCD, 0xC7, 0xF9, 0x89, 0xCF, 0xFF, 0x03};
/*    4*/const uint8_t spFOUR[]     PROGMEM = {0x08, 0x68, 0x21, 0x0D, 0x03, 0x04, 0x28, 0xCE, 0x92, 0x03, 0x23, 0x4A, 0xCA, 0xA6, 0x1C, 0xDA, 0xAD, 0xB4, 0x70, 0xED, 0x19, 0x64, 0xB7, 0xD3, 0x91, 0x45, 0x51, 0x35, 0x89, 0xEA, 0x66, 0xDE, 0xEA, 0xE0, 0xAB, 0xD3, 0x29, 0x4F, 0x1F, 0xFA, 0x52, 0xF6, 0x90, 0x52, 0x3B, 0x25, 0x7F, 0xDD, 0xCB, 0x9D, 0x72, 0x72, 0x8C, 0x79, 0xCB, 0x6F, 0xFA, 0xD2, 0x10, 0x9E, 0xB4, 0x2C, 0xE1, 0x4F, 0x25, 0x70, 0x3A, 0xDC, 0xBA, 0x2F, 0x6F, 0xC1, 0x75, 0xCB, 0xF2, 0xFF};
/*    5*/const uint8_t spFIVE[]     PROGMEM = {0x08, 0x68, 0x4E, 0x9D, 0x02, 0x1C, 0x60, 0xC0, 0x8C, 0x69, 0x12, 0xB0, 0xC0, 0x28, 0xAB, 0x8C, 0x9C, 0xC0, 0x2D, 0xBB, 0x38, 0x79, 0x31, 0x15, 0xA3, 0xB6, 0xE4, 0x16, 0xB7, 0xDC, 0xF5, 0x6E, 0x57, 0xDF, 0x54, 0x5B, 0x85, 0xBE, 0xD9, 0xE3, 0x5C, 0xC6, 0xD6, 0x6D, 0xB1, 0xA5, 0xBF, 0x99, 0x5B, 0x3B, 0x5A, 0x30, 0x09, 0xAF, 0x2F, 0xED, 0xEC, 0x31, 0xC4, 0x5C, 0xBE, 0xD6, 0x33, 0xDD, 0xAD, 0x88, 0x87, 0xE2, 0xD2, 0xF2, 0xF4, 0xE0, 0x16, 0x2A, 0xB2, 0xE3, 0x63, 0x1F, 0xF9, 0xF0, 0xE7, 0xFF, 0x01};
/*    6*/const uint8_t spSIX[]      PROGMEM = {0x04, 0xF8, 0xAD, 0x4C, 0x02, 0x16, 0xB0, 0x80, 0x06, 0x56, 0x35, 0x5D, 0xA8, 0x2A, 0x6D, 0xB9, 0xCD, 0x69, 0xBB, 0x2B, 0x55, 0xB5, 0x2D, 0xB7, 0xDB, 0xFD, 0x9C, 0x0D, 0xD8, 0x32, 0x8A, 0x7B, 0xBC, 0x02, 0x00, 0x03, 0x0C, 0xB1, 0x2E, 0x80, 0xDF, 0xD2, 0x35, 0x20, 0x01, 0x0E, 0x60, 0xE0, 0xFF, 0x01};
/*    7*/const uint8_t spSEVEN[]    PROGMEM = {0x0C, 0xF8, 0x5E, 0x4C, 0x01, 0xBF, 0x95, 0x7B, 0xC0, 0x02, 0x16, 0xB0, 0xC0, 0xC8, 0xBA, 0x36, 0x4D, 0xB7, 0x27, 0x37, 0xBB, 0xC5, 0x29, 0xBA, 0x71, 0x6D, 0xB7, 0xB5, 0xAB, 0xA8, 0xCE, 0xBD, 0xD4, 0xDE, 0xA6, 0xB2, 0x5A, 0xB1, 0x34, 0x6A, 0x1D, 0xA7, 0x35, 0x37, 0xE5, 0x5A, 0xAE, 0x6B, 0xEE, 0xD2, 0xB6, 0x26, 0x4C, 0x37, 0xF5, 0x4D, 0xB9, 0x9A, 0x34, 0x39, 0xB7, 0xC6, 0xE1, 0x1E, 0x81, 0xD8, 0xA2, 0xEC, 0xE6, 0xC7, 0x7F, 0xFE, 0xFB, 0x7F};
/*    8*/const uint8_t spEIGHT[]    PROGMEM = {0x65, 0x69, 0x89, 0xC5, 0x73, 0x66, 0xDF, 0xE9, 0x8C, 0x33, 0x0E, 0x41, 0xC6, 0xEA, 0x5B, 0xEF, 0x7A, 0xF5, 0x33, 0x25, 0x50, 0xE5, 0xEA, 0x39, 0xD7, 0xC5, 0x6E, 0x08, 0x14, 0xC1, 0xDD, 0x45, 0x64, 0x03, 0x00, 0x80, 0x00, 0xAE, 0x70, 0x33, 0xC0, 0x73, 0x33, 0x1A, 0x10, 0x40, 0x8F, 0x2B, 0x14, 0xF8, 0x7F};
/*    9*/const uint8_t spNINE[]     PROGMEM = {0xE6, 0xA8, 0x1A, 0x35, 0x5D, 0xD6, 0x9A, 0x35, 0x4B, 0x8C, 0x4E, 0x6B, 0x1A, 0xD6, 0xA6, 0x51, 0xB2, 0xB5, 0xEE, 0x58, 0x9A, 0x13, 0x4F, 0xB5, 0x35, 0x67, 0x68, 0x26, 0x3D, 0x4D, 0x97, 0x9C, 0xBE, 0xC9, 0x75, 0x2F, 0x6D, 0x7B, 0xBB, 0x5B, 0xDF, 0xFA, 0x36, 0xA7, 0xEF, 0xBA, 0x25, 0xDA, 0x16, 0xDF, 0x69, 0xAC, 0x23, 0x05, 0x45, 0xF9, 0xAC, 0xB9, 0x8F, 0xA3, 0x97, 0x20, 0x73, 0x9F, 0x54, 0xCE, 0x1E, 0x45, 0xC2, 0xA2, 0x4E, 0x3E, 0xD3, 0xD5, 0x3D, 0xB1, 0x79, 0x24, 0x0D, 0xD7, 0x48, 0x4C, 0x6E, 0xE1, 0x2C, 0xDE, 0xFF, 0x0F};
/*   10*/const uint8_t spTEN[]      PROGMEM = {0x0E, 0x38, 0x3C, 0x2D, 0x00, 0x5F, 0xB6, 0x19, 0x60, 0xA8, 0x90, 0x93, 0x36, 0x2B, 0xE2, 0x99, 0xB3, 0x4E, 0xD9, 0x7D, 0x89, 0x85, 0x2F, 0xBE, 0xD5, 0xAD, 0x4F, 0x3F, 0x64, 0xAB, 0xA4, 0x3E, 0xBA, 0xD3, 0x59, 0x9A, 0x2E, 0x75, 0xD5, 0x39, 0x6D, 0x6B, 0x0A, 0x2D, 0x3C, 0xEC, 0xE5, 0xDD, 0x1F, 0xFE, 0xB0, 0xE7, 0xFF, 0x03};
/*   11*/const uint8_t spELEVEN[]   PROGMEM = {0xA5, 0xEF, 0xD6, 0x50, 0x3B, 0x67, 0x8F, 0xB9, 0x3B, 0x23, 0x49, 0x7F, 0x33, 0x87, 0x31, 0x0C, 0xE9, 0x22, 0x49, 0x7D, 0x56, 0xDF, 0x69, 0xAA, 0x39, 0x6D, 0x59, 0xDD, 0x82, 0x56, 0x92, 0xDA, 0xE5, 0x74, 0x9D, 0xA7, 0xA6, 0xD3, 0x9A, 0x53, 0x37, 0x99, 0x56, 0xA6, 0x6F, 0x4F, 0x59, 0x9D, 0x7B, 0x89, 0x2F, 0xDD, 0xC5, 0x28, 0xAA, 0x15, 0x4B, 0xA3, 0xD6, 0xAE, 0x8C, 0x8A, 0xAD, 0x54, 0x3B, 0xA7, 0xA9, 0x3B, 0xB3, 0x54, 0x5D, 0x33, 0xE6, 0xA6, 0x5C, 0xCB, 0x75, 0xCD, 0x5E, 0xC6, 0xDA, 0xA4, 0xCA, 0xB9, 0x35, 0xAE, 0x67, 0xB8, 0x46, 0x40, 0xB6, 0x28, 0xBB, 0xF1, 0xF6, 0xB7, 0xB9, 0x47, 0x20, 0xB6, 0x28, 0xBB, 0xFF, 0x0F};
/*   12*/const uint8_t spTWELVE[]   PROGMEM = {0x09, 0x98, 0xDA, 0x22, 0x01, 0x37, 0x78, 0x1A, 0x20, 0x85, 0xD1, 0x50, 0x3A, 0x33, 0x11, 0x81, 0x5D, 0x5B, 0x95, 0xD4, 0x44, 0x04, 0x76, 0x9D, 0xD5, 0xA9, 0x3A, 0xAB, 0xF0, 0xA1, 0x3E, 0xB7, 0xBA, 0xD5, 0xA9, 0x2B, 0xEB, 0xCC, 0xA0, 0x3E, 0xB7, 0xBD, 0xC3, 0x5A, 0x3B, 0xC8, 0x69, 0x67, 0xBD, 0xFB, 0xE8, 0x67, 0xBF, 0xCA, 0x9D, 0xE9, 0x74, 0x08, 0xE7, 0xCE, 0x77, 0x78, 0x06, 0x89, 0x32, 0x57, 0xD6, 0xF1, 0xF1, 0x8F, 0x7D, 0xFE, 0x1F};
/*   13*/const uint8_t spTHIR_[]    PROGMEM = {0x04, 0xA8, 0xBE, 0x5C, 0x00, 0xDD, 0xA5, 0x11, 0xA0, 0xFA, 0x72, 0x02, 0x74, 0x97, 0xC6, 0x01, 0x09, 0x9C, 0xA6, 0xAB, 0x30, 0x0D, 0xCE, 0x7A, 0xEA, 0x6A, 0x4A, 0x39, 0x35, 0xFB, 0xAA, 0x8B, 0x1B, 0xC6, 0x76, 0xF7, 0xAB, 0x2E, 0x79, 0x19, 0xCA, 0xD5, 0xEF, 0xCA, 0x57, 0x08, 0x14, 0xA1, 0xDC, 0x45, 0x64, 0x03, 0x00, 0xC0, 0xFF, 0x03};
/*   14*/const uint8_t spFIF_[]     PROGMEM = {0x08, 0x98, 0x31, 0x93, 0x02, 0x1C, 0xE0, 0x80, 0x07, 0x5A, 0xD6, 0x1C, 0x6B, 0x78, 0x2E, 0xBD, 0xE5, 0x2D, 0x4F, 0xDD, 0xAD, 0xAB, 0xAA, 0x6D, 0xC9, 0x23, 0x02, 0x56, 0x4C, 0x93, 0x00, 0x05, 0x10, 0x90, 0x89, 0x31, 0xFC, 0x3F};
/*   15*/const uint8_t sp_TEEN[]    PROGMEM = {0x09, 0x58, 0x2A, 0x25, 0x00, 0xCB, 0x9F, 0x95, 0x6C, 0x14, 0x21, 0x89, 0xA9, 0x78, 0xB3, 0x5B, 0xEC, 0xBA, 0xB5, 0x23, 0x13, 0x46, 0x97, 0x99, 0x3E, 0xD6, 0xB9, 0x2E, 0x79, 0xC9, 0x5B, 0xD8, 0x47, 0x41, 0x53, 0x1F, 0xC7, 0xE1, 0x9C, 0x85, 0x54, 0x22, 0xEC, 0xFA, 0xDB, 0xDD, 0x23, 0x93, 0x49, 0xB8, 0xE6, 0x78, 0xFF, 0x3F};
/*   16*/const uint8_t spTWENTY[]   PROGMEM = {0x0A, 0xE8, 0x4A, 0xCD, 0x01, 0xDB, 0xB9, 0x33, 0xC0, 0xA6, 0x54, 0x0C, 0xA4, 0x34, 0xD9, 0xF2, 0x0A, 0x6C, 0xBB, 0xB3, 0x53, 0x0E, 0x5D, 0xA6, 0x25, 0x9B, 0x6F, 0x75, 0xCA, 0x61, 0x52, 0xDC, 0x74, 0x49, 0xA9, 0x8A, 0xC4, 0x76, 0x4D, 0xD7, 0xB1, 0x76, 0xC0, 0x55, 0xA6, 0x65, 0xD8, 0x26, 0x99, 0x5C, 0x56, 0xAD, 0xB9, 0x25, 0x23, 0xD5, 0x7C, 0x32, 0x96, 0xE9, 0x9B, 0x20, 0x7D, 0xCB, 0x3C, 0xFA, 0x55, 0xAE, 0x99, 0x1A, 0x30, 0xFC, 0x4B, 0x3C, 0xFF, 0x1F};
/*   17*/const uint8_t spT[]        PROGMEM = {0x01, 0xD8, 0xB6, 0xDD, 0x01, 0x2F, 0xF4, 0x38, 0x60, 0xD5, 0xD1, 0x91, 0x4D, 0x97, 0x84, 0xE6, 0x4B, 0x4E, 0x36, 0xB2, 0x10, 0x67, 0xCD, 0x19, 0xD9, 0x2C, 0x01, 0x94, 0xF1, 0x78, 0x66, 0x33, 0xEB, 0x79, 0xAF, 0x7B, 0x57, 0x87, 0x36, 0xAF, 0x52, 0x08, 0x9E, 0x6B, 0xEA, 0x5A, 0xB7, 0x7A, 0x94, 0x73, 0x45, 0x47, 0xAC, 0x5A, 0x9C, 0xAF, 0xFF, 0x07};
/*   18*/const uint8_t spHUNDRED[]  PROGMEM = {0x04, 0xC8, 0x7E, 0x5C, 0x02, 0x0A, 0xA8, 0x62, 0x43, 0x03, 0xA7, 0xA8, 0x62, 0x43, 0x4B, 0x97, 0xDC, 0xF2, 0x14, 0xC5, 0xA7, 0x9B, 0x7A, 0xD3, 0x95, 0x37, 0xC3, 0x1E, 0x16, 0x4A, 0x66, 0x36, 0xF3, 0x5A, 0x89, 0x6E, 0xD4, 0x30, 0x55, 0xB5, 0x32, 0xB7, 0x31, 0xB5, 0xC1, 0x69, 0x2C, 0xE9, 0xF7, 0xBC, 0x96, 0x12, 0x39, 0xD4, 0xB5, 0xFD, 0xDA, 0x9B, 0x0F, 0xD1, 0x90, 0xEE, 0xF5, 0xE4, 0x17, 0x02, 0x45, 0x28, 0x77, 0x11, 0xD9, 0x40, 0x9E, 0x45, 0xDD, 0x2B, 0x33, 0x71, 0x7A, 0xBA, 0x0B, 0x13, 0x95, 0x2D, 0xF9, 0xF9, 0x7F};
/*   19*/const uint8_t spTHOUSAND[] PROGMEM = {0x0C, 0xE8, 0x2E, 0xD4, 0x02, 0x06, 0x98, 0xD2, 0x55, 0x03, 0x16, 0x68, 0x7D, 0x17, 0xE9, 0x6E, 0xBC, 0x65, 0x8C, 0x45, 0x6D, 0xA6, 0xE9, 0x96, 0xDD, 0xDE, 0xF6, 0xB6, 0xB7, 0x5E, 0x75, 0xD4, 0x93, 0xA5, 0x9C, 0x7B, 0x57, 0xB3, 0x6E, 0x7D, 0x12, 0x19, 0xAD, 0xDC, 0x29, 0x8D, 0x4F, 0x93, 0xB4, 0x87, 0xD2, 0xB6, 0xFC, 0xDD, 0xAC, 0x22, 0x56, 0x02, 0x70, 0x18, 0xCA, 0x18, 0x26, 0xB5, 0x90, 0xD4, 0xDE, 0x6B, 0x29, 0xDA, 0x2D, 0x25, 0x17, 0x8D, 0x79, 0x88, 0xD4, 0x48, 0x79, 0x5D, 0xF7, 0x74, 0x75, 0xA1, 0x94, 0xA9, 0xD1, 0xF2, 0xED, 0x9E, 0xAA, 0x51, 0xA6, 0xD4, 0x9E, 0x7F, 0xED, 0x6F, 0xFE, 0x2B, 0xD1, 0xC7, 0x3D, 0x89, 0xFA, 0xB7, 0x0D, 0x57, 0xD3, 0xB4, 0xF5, 0x37, 0x55, 0x37, 0x2E, 0xE6, 0xB2, 0xD7, 0x57, 0xFF, 0x0F};
/*   20*/const uint8_t spAND[]      PROGMEM = {0xA9, 0x6B, 0x21, 0xB9, 0x22, 0x66, 0x9F, 0xAE, 0xC7, 0xE1, 0x70, 0x7B, 0x72, 0xBB, 0x5B, 0xDF, 0xEA, 0x56, 0xBB, 0x5C, 0x65, 0xCB, 0x66, 0xC5, 0x3D, 0x67, 0xD7, 0xAB, 0x6D, 0x2E, 0x64, 0x30, 0x93, 0xEE, 0xB1, 0xCD, 0x3D, 0x92, 0xB9, 0x9A, 0xDA, 0xB2, 0x8E, 0x40, 0x12, 0x9A, 0x6A, 0xEB, 0x96, 0x8F, 0x78, 0x98, 0xB3, 0x2A, 0xB4, 0xD3, 0x48, 0xAA, 0x2F, 0x7D, 0xA7, 0x7B, 0xFB, 0x0C, 0x73, 0x71, 0x5C, 0xCE, 0x6E, 0x5C, 0x52, 0x6C, 0x73, 0x79, 0x9A, 0x13, 0x4B, 0x89, 0x45, 0xE9, 0x6E, 0x49, 0x42, 0xA9, 0x57, 0xFF, 0x3F};
/*   21*/const uint8_t spPAUSE1[]   PROGMEM = {0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F};
/*   22*/const uint8_t spZERO[]     PROGMEM = {0x69, 0xFB, 0x59, 0xDD, 0x51, 0xD5, 0xD7, 0xB5, 0x6F, 0x0A, 0x78, 0xC0, 0x52, 0x01, 0x0F, 0x50, 0xAC, 0xF6, 0xA8, 0x16, 0x15, 0xF2, 0x7B, 0xEA, 0x19, 0x47, 0xD0, 0x64, 0xEB, 0xAD, 0x76, 0xB5, 0xEB, 0xD1, 0x96, 0x24, 0x6E, 0x62, 0x6D, 0x5B, 0x1F, 0x0A, 0xA7, 0xB9, 0xC5, 0xAB, 0xFD, 0x1A, 0x62, 0xF0, 0xF0, 0xE2, 0x6C, 0x73, 0x1C, 0x73, 0x52, 0x1D, 0x19, 0x94, 0x6F, 0xCE, 0x7D, 0xED, 0x6B, 0xD9, 0x82, 0xDC, 0x48, 0xC7, 0x2E, 0x71, 0x8B, 0xBB, 0xDF, 0xFF, 0x1F};
/*   23*/const uint8_t spMINUS[]    PROGMEM = {0xE6, 0x28, 0xC4, 0xF8, 0x44, 0x9A, 0xFB, 0xCD, 0xAD, 0x8D, 0x2A, 0x4E, 0x4A, 0xBC, 0xB8, 0x8C, 0xB9, 0x8A, 0xA9, 0x48, 0xED, 0x72, 0x87, 0xD3, 0x74, 0x3B, 0x1A, 0xA9, 0x9D, 0x6F, 0xB3, 0xCA, 0x5E, 0x8C, 0xC3, 0x7B, 0xF2, 0xCE, 0x5A, 0x5E, 0x35, 0x66, 0x5A, 0x3A, 0xAE, 0x55, 0xEB, 0x9A, 0x57, 0x75, 0xA9, 0x29, 0x6B, 0xEE, 0xB6, 0xD5, 0x4D, 0x37, 0xEF, 0xB5, 0x5D, 0xC5, 0x95, 0x84, 0xE5, 0xA6, 0xFC, 0x30, 0xE0, 0x97, 0x0C, 0x0D, 0x58, 0x40, 0x03, 0x1C, 0xA0, 0xC0, 0xFF, 0x03};
/*   24*/const uint8_t spMILLI[]    PROGMEM = {0x6E, 0xF0, 0x8A, 0xB3, 0x4B, 0xEB, 0xC6, 0xAE, 0x36, 0xA7, 0x1A, 0x3A, 0x54, 0x53, 0xD6, 0xDC, 0xEC, 0x66, 0x23, 0xDF, 0x58, 0x26, 0x43, 0xB4, 0xCD, 0xEA, 0x74, 0x5D, 0x94, 0x46, 0xF0, 0x96, 0x3B, 0x9D, 0x79, 0x98, 0x26, 0x75, 0xDB, 0xB3, 0xD7, 0xB6, 0xF5, 0x90, 0xA8, 0x91, 0x9F, 0xEA, 0x9E, 0xEE, 0xE9, 0x9B, 0x20, 0x7D, 0xCB, 0xFF, 0x03};
/*   25*/const uint8_t spVOLTS[]    PROGMEM = {0xA0, 0xDA, 0xA2, 0xB2, 0x3A, 0x44, 0x55, 0x9C, 0xFA, 0xB0, 0xBA, 0x46, 0x72, 0xDA, 0xD1, 0xDB, 0xAE, 0x47, 0x59, 0x61, 0xED, 0x28, 0x79, 0xED, 0x45, 0xAF, 0x5A, 0xDF, 0x60, 0xF4, 0x39, 0x69, 0xAB, 0x63, 0xD9, 0x3B, 0xD2, 0xBC, 0x24, 0xA5, 0xF5, 0xB6, 0x0F, 0x80, 0x01, 0x3E, 0x63, 0x65, 0xC0, 0x5F, 0x63, 0x12, 0x90, 0x80, 0x06, 0x24, 0x20, 0x01, 0x0E, 0xFC, 0x3F};
/*index*/const uint8_t * indexArray [] PROGMEM = {NOTHING,spONE,spTWO,spTHREE,spFOUR,spFIVE,spSIX,spSEVEN,spEIGHT,spNINE,spTEN,spELEVEN,spTWELVE,spTHIR_,spFIF_,sp_TEEN,spTWENTY,spT,spHUNDRED,spTHOUSAND,spAND,spPAUSE1,spZERO,spMINUS,spMILLI,spVOLTS};
#endif

uint8_t numberWords (int * array, int n, uint8_t & c) {
  if (n < 0) {
    array [c] = 23; //MINUS
    c += 1;
    n = 0-n;
  }
  byte pattern = 0;
  if (n >= 1000) {
    int thousands = n / 1000;
    numberWords (array, thousands, c); 
    array [c] = 19;
    c += 1;
    pattern |= 1 << 2;
    n %= 1000; if (n == 0) {
      return 1;
    }
  }
  if (n >= 100) {
    int hundreds = n / 100;
    numberWords (array, hundreds, c); 
    array [c] = 18;
    c += 1;
    pattern |= 1 << 1;
    n %= 100; if (n == 0) {
      return 1;
    }
  }
  if (n >= 10) {
  { if ( (pattern & (1 << 2)) || (pattern & (1 << 1)) ) {
        array [c] = 20; //AND
        c += 1;
      }
    }
  { if ( (n >= 60) ||  ( (n >= 40) && (n <= 49) ) ) {
        array [c]   = n / 10;
        array [c + 1] = 17; //T
        c += 2;
        pattern |= 1;
        n %= 10; if (n == 0) {
          return 1;
        }
      }
    }
    { if (n >= 50) {
        array [c]   = 14;
        array [c + 1] = 17; //T
        c += 2;
        pattern |= 1;
        n %= 10; if (n == 0) {
          return 1;
        }
      }
    }
    { if (n >= 30) {
        array [c]   = 13;
        array [c + 1] = 17; //T
        c += 2;
        pattern |= 1;
        n %= 10; if (n == 0) {
          return 1;
        }
      }
    }
  { if (n >= 20) {
        array [c]   = 16; //TWENTY
        c += 1;
        pattern |= 1;
        n %= 10; if (n == 0) {
          return 1;
        }
      }
    }
  { if ( (n == 14) || ( (n >= 16) && (n <= 19) ) ) {
        array [c]   = n % 10;
        array [c + 1] = 15; //TEEN
        c += 2;
        return 1;
      }
    }
  { if (n == 15) {
        array [c]   = 14;
        array [c + 1] = 15; //TEEN
        c += 2;
        return 1;
      }
    }{ if (n == 13) {
        array [c]   = 13;
        array [c + 1] = 15; //TEEN
        c += 2;
        return 1;
      }
    }
 { if (n == 12) {
        array [c]   = 12;
        c += 1;
        return 1;
      }
    }
  { if (n == 11) {
        array [c]   = 11;
        c += 1;
        return 1;
      }
    }
  { if (n == 10) {
        array [c]   = 10;
        c += 1;
        return 1;
      }
    }
  }
  if (    ( (pattern & (1 << 2)) || (pattern & (1 << 1))  ) &&  (!(pattern & 1))      )  {
    array [c] = 20; //AND
    c += 1;
  }
  array [c]   = n;
  c += 1;
  return 1;
}

Talkie voice;

void setup() {
Serial.begin(9600);
  pinMode(5, OUTPUT);
  digitalWrite(5, 1);//propshield amp enable code
}

void loop() {
  int wordarray [24];
  int number = 845911;
  //int number = analogRead(0) * 5.000 / 1.023; // voltage
  uint8_t counter = 0;
  if (number == 0) {wordarray[0] = 22; counter += 1;} //zero, say ZERO
  else {numberWords(wordarray, number, counter);} // fill number word array
  wordarray [counter] = 24; wordarray [counter + 1] = 25; counter +=2; //add in MILLIVOLTS ...
  arrayInterface (wordarray, counter); // "SAYQ"
  // delay (50);
}

void arrayInterface (int * wordArray, uint8_t wordArraySize) {
  for (uint8_t i = 0; i < wordArraySize; i++) {
    voice.sayQ (indexArray[wordArray[i]]);
  }
}
 
Last edited:
@Adrian - good fun. The voltmeter example was existing with the library and uses recursion to solve later parts of the problem in a cool way - without duplicating the effort as you go from higher order numbers down.

Interesting how it saved much memory - you did in your code what the queue portion I wrote in .sayQ() does - good practice. It seemed like a common issue when assembling a group of text - as I saw in my early examples - so I decided it would best be built into the library itself so it wouldn't need to be re-created. Whenever you call sayQ() it returns how many empty spaces are in the queue - I settled on 24 as that made it take about a round 100 bytes of RAM - and 24 sounds can be a long wait - and is easily supplemented as needed - or it could be expanded in the library. The other thing I added at the last minute was having .active() return the number of active items in the queue yet to play.

instead of writing two lines:: "array [c] = n; and c += 1;" you could replace that with "array [c++] = n;" to tell it to increment the variable c AFTER it is used each time since you always do that when adding an item. It'll make no difference to the compiler - but will shorten the text on your screen.
 
I haven't tested, but I'm pretty sure Talkie can't work on Teensy 2.0. It uses AVR timer2.

Might work on Teensy++ 2.0, which does have that timer.
 
@defragster thanks for the pointers, and thanks for your continued work! a 1 a 2 a 1 2 3 4 ...
 
@ebsebs ... i use a teensy LC for talkie ... works good... i suspect a higher quality DAC would be 'better'.... but the possible drawback is if you are going to utilise a large sample library ... the LC has less memory than a 3.x .... So I guess it will depend on what your intentions are (if you are thinking of 'upgrading') ....
 
I haven't tested, but I'm pretty sure Talkie can't work on Teensy 2.0. It uses AVR timer2.

Might work on Teensy++ 2.0, which does have that timer.

There is a pull request if you wanted to put it into 1.28b2. I ran my T_3.2 at 24MHz and it ran fine - not sure if the 16MHz AVR might stutter on the chaining data update I did to stop the blocking.
 
Hi everyone. I've just read the above thread about the Talkie library on Teensy 3.2
We have some Teensy 3.2's and a bunch of audio boards. Any ideas how I'd go about getting the talkie library to output through the Audio board's headphone socket?
Thanks,
Steve.
 
ideas how I'd go about getting the talkie library to output through the Audio board's headphone socket?

Sorry, that's not supported. Talkie only outputs to the DAC/A14 pin. It doesn't have any code to send as I2S format to the chip on the audio shield.
 
I just discovered this library while browsing the examples in the Arduino IDE.
Great work! The demos are funny and put a huge smile on my face, hah!

I ran talkie on a Teensy 3.6 and the examples work well. Also the code posted above worked.

My Signal Path:
DAC0 (A21) pin >> alligator clip wires >> RCA to 1/8" stereo jack >> line-in on laptop PC, >> Sony HDTV, audio is fine for what it is.

This library and member enhancements above really catch the essence of the hacker spirit, great stuff and funny too.

I used to design interactive voice response (IVR) or simply put, telephone voice mail and similiar platforms for commercial use.
I wonder if anyone heard thought of using Teensy 3.x as a voice-over-IP end point, like for voice mail, IVR, etc, via some minimalist voice over IP stack?

Talkie could be used to play numbers and other values that are decided on the fly, like "The current soil temperature is 75 degrees"

A voice over IP telephony library would probably use an SIP stack for VOIP call control, and RTP protocol for
the audio in and out.

Maybe this was a bit much for Teensy 3.2, and as such not considered by anyone, but maybe Teensy 3.6 is fast enough to make it possible?

Disclaimer: the following is merely a dream of possibilities and in no way reflects my expectations that someone built the monster described below,
but to inspire and spark ideas in the minds of forum members who are good enough programmers to consider the idea.

Uncompressed telephony audio streams are only 8 bits @ 8000 samples per second, ulaw PCM.
(64,000 bits per second, that's only 8 kilobytes per second each direction).

That's alot less than playing 4 hi-fi audio channels at 44.1K samples/sec 16 bits each, a favorite quoted Teensy capability.

Maybe with Teensy 3.5/3.6 now available, someone could justify the effort to port an open source SIP call library over to Teensy, and mod talkie
while they are at it, to stream such 8k audio out to either the audio library, as requested above, or to a telephony library.

I would do it so far as interest and motivation is concerned, but I only know the general structure; I'm not that good a programmer yet to take on that beast.

Non blocking talkie would be a great candidate for speech synthesis on VOIP role I suspect, assuming and I know it's a big job, that someone ports a telephony library to Teensy.

A basic VOIP library should handle recording/playback on the line, play voice prompts, and handle touch tone detection / collection of digits, with the ability
to interrupt the current playback or recording when a touch tone is detected.

Finally, a user programmed API could wrap the complexity so users can make a call handling script equivalent to what voice XML does but much simpler.
The end result is you could call your Teensy's phone number from any phone and interact with voice menus, leave voice messages on the card or change
settings of remote sensor, etc, and receive spoken voice telemetry over the phone. Teensy could call your cell phone if something significant happens on a sensor,
or any internet originated trigger, etc, and then speak about what event happened, etc.

I will keep this idea in mind for when I get up to speed, but will support any effort in that direction as a former general user-level programmer of such beasts.

Maybe an alternative is to wire a suitable voice over IP module to Teensy, let it handle the SIP calls, and pass audio in and out to teensy, and some control protocol. Hmm.
I wonder about those cheap VOIP phone dongles or similiar little self contained modules as possible candidates. Audio and signaling need be considered to connect to Teensy.

/End of wild idea.

Now, off to make talkie say more funny things...
 
Last edited:
As far as i know, there are cheap GSM-Modules from china (aliexpr*ss) available - much easier to use than voice over ip.
Or hack a analog phone...
 
Yeah, that's something I want to play with too, saw some examples on Adafruit, probably cheaper on AliExpress, etc.
Definitely the choice if it's outside and away from other networks, like a wildlife cam, etc.

I like the idea of VoIP because of easy and cheap multi-channel capabilities built in to the protocol stack, and that even cell phones
can run VoIP software apps for a self-made communication network riding on IP, bypassing the need in many cases to buy monthly
services for connectivity.
Such service fees easily outweigh the cost of the particular hardware in this case.

Speaking of enabling Teensy 3.x with wireless data-
I successfully got an ESP8266 to connect as an SPI slave to a Teensy 3.6 master recently,
as part of a larger 256 pixel photo diode array sensor reading project.

Bits flow fast like this:
sensor >> Teensy 3.6 >> SPI >> ESP8266 >> WiFi UDP packets >> home router >> laptop >> Processing graphical plot of pixel data.

I am seeing roughly about 150 frames (complete sensor reads, 256 samples, 2 bytes each sample) per second.
I will post it soon after I clean it up.

(edit)
I posted my first version of the TSL1402R sensor reader, which simply has the Teensy 3.6 read the sendor and send the data via USB serial.
Soon I will publish the more complex one described above, invoking SPI to WiFi module for Teensy 3.6.
https://forum.pjrc.com/threads/3905...l-Sensor-using-Teensy-3-x?p=121782#post121782
(/edit)

To avoid voice service gateway monthly fees, you just "dial" an IP address on most SIP VoIP apps, and the call(s) would be all IP voice
to the Teensy.

It would be cool to have a web based sip client enabled to "call my gadget for a live demo" kind of thing.

If it could handle, say, 5 to 10 calls at the same time, heck, you have a platform that bridges Arduino to VoIP
for doing call based embedded control/telemetry of all sorts with touch tone menus, etc:

"Press 1 to run blinky test. Press 2 to make robot fetch beer. Press 3, to hear top news headlines and start coffee" etc.

Maybe a vending machine app? Call to dispense your free drink, and marketing gets the phone number, heh.

World's smallest VoIP PBX/office phone system/IVR platform on a Teensy 3.6? Linux Asterisk, eat your heart out!

Probably better to run on a Raspberry PI for a more "serious" micro PBX, but being very small and super-inexpensive as a Teensy,
captures the essence of internet of things, and can be stuffed into tiny places.

Heh, call my drone direct to order a pizza delivered. Just kidding, sort of.
You could pass VoIP calls through a drone for disaster communications, and use it as a tower repeater for range.
Pretty strong option if it can handle a bunch of calls at the same time, and maybe tether-powered so it can stay up a long time.
Or simply put it on a rooftop or tower as a self-contained low power solar makeshift relay station, etc.

The boards like Teensy 3.5/3.6 and ESP8266 are so cheap and fast, these kind of applications historically reserved for bigger and badder
boards are creeping into this super small embedded hobbyist realm, opening up possibilities.

I love the idea of an Arduino telephony VoIP library...

Funny what one cool talking voice library can trigger in one's head.
 
Last edited:
Re: ideas how I'd go about getting the talkie library to output through the Audio board's headphone socket?

Sorry, that's not supported. Talkie only outputs to the DAC/A14 pin. It doesn't have any code to send as I2S format to the chip on the audio shield.

I think you could jumper the Teensy DAC to LineIn L of audio adaptor and play through headphones, see similar example with TTS
https://forum.pjrc.com/threads/4458...)-Library-Port?p=145790&viewfull=1#post145790
 
Last edited:
hi there, new (potential) user.

so i tried the original talkie library on an arduino uno, works great. then i started adding midi in and midi control which worked not so great because of the blockiness :) (part of it can be solved by putting the MIDI.read(); calls also in the do while brackets... still it is far from ideal or clean.

the non blocking version does not correctly work on an arduino uno. speech is output but at maximum rate, so a whole phrase is only a short noise of 150ms or so :)

so my questions are:

-will midi control (old school serial din, and usb) work with the teensy and the non blocking library? (i guess so) i would like to choose phrases/words, alter pitch and speed and have different playmodes:
-start and stop on note On, note Off. word repeated as long as no note off is received.
-onesot mode: just play the word once you get a noteon don't repeat don't abort even when a note off is received before word is finished
-maybe a random mode that just spits out "garbage" (random values for the synthK variables)

-can i change the speed of the spoken words and also the pitch? (in the original library i just modified OCR1A to get different pitched vocals and i altered the delay(); to speedup or slowdown the speech) so i guess the question is, is it easy to alter the speed at which sayisr() is called?

thanks
 
hi there, new (potential) user.

so i tried the original talkie library on an arduino uno, works great. then i started adding midi in and midi control which worked not so great because of the blockiness :) (part of it can be solved by putting the MIDI.read(); calls also in the do while brackets... still it is far from ideal or clean.

the non blocking version does not correctly work on an arduino uno. speech is output but at maximum rate, so a whole phrase is only a short noise of 150ms or so :)

so my questions are:

-will midi control (old school serial din, and usb) work with the teensy and the non blocking library? (i guess so) i would like to choose phrases/words, alter pitch and speed and have different playmodes:
-start and stop on note On, note Off. word repeated as long as no note off is received.
-onesot mode: just play the word once you get a noteon don't repeat don't abort even when a note off is received before word is finished
-maybe a random mode that just spits out "garbage" (random values for the synthK variables)

-can i change the speed of the spoken words and also the pitch? (in the original library i just modified OCR1A to get different pitched vocals and i altered the delay(); to speedup or slowdown the speech) so i guess the question is, is it easy to alter the speed at which sayisr() is called?

thanks

just a quick update...i put the MIDI.read(); into the ISR(TIMER1_COMPA_vect) {} and it works very well so far on the arduino uno with the original library. nice!
still interested how feasible this is on the teensy :)
 
Paul did the Teensy ARM specific Timer part - I added the non blocking queue. The Teensy should be able to do both at the same time as long as they don't have any conflicting resources. If the rate of timer firing is altered - to change pitch? - it should work fine as the queueing I did counts timed events to load the next batch of data. If the events happen slower or faster - the non-blocking playback should follow along without issue - with the sound being 'skewed' { as desired }.

But the data is just a stream - so repeating a word would have to be an isolated sample - that word could repeat over and over until note off is received. It isn't something that the queueing code would do programmatically. IIRC the queue can be filled and emptied and monitored for its state. Those features should allow much of what the sketch would want to do. Since it does not block - this could be done on the fly in the sketch.
 
Last edited:
Just found this library - and wow!. Thanks defragster and Paul. Any chance it could be written to NOT use analog out and instead one or two PWM pins? This way I could add voice to any of my existing Teensy projects by only soldering a speaker two one or two pins on the teensy, obviating the need for an amplifier purchase.

--Rudy
 
An integration into the audiolibrary would be best, as it lets you choose the output, and apply filters, mixers, effects...
 
Status
Not open for further replies.
Back
Top