Talkie speech library

Status
Not open for further replies.
That example I didn't open would not run right at all non blocking... Vocab_UK_Acorn.ino, as it is written as each. say would quit as the next was started

<edit> - it'll work now.
 
Last edited:
The acorn voice is great. It has a good vocabulary. I have it saying "This is not a negative parameter, this is not a negative number, illegal cassette, illegal cassette" Hilarious ...sounds kind of like some of those old school House overdubs from the 90s. if only I could upload sound files .......
 
adrian - maybe you can put it in a zip?

I update my GitHub: Talkie now with an active method that yields when called so the system won't freeze in a tight loop.

Old samples calling voice.set() work as before - it still blocks

To get non blocking sounds call voice.setQ(), check voice.active() for 0 return to know that sound is complete, calling with new sound will abort any running sound.
 
Last edited:
That sounds like a great idea. :)

Okay - good - you'll see I just restored the original behavior as it broke examples (I hadn't tried). The sayQ() method is in place - just needs a simple ring buffer - implemented inside a 125usec interrupt - outside the class - to end one sound and start the next.

@Paul: let me know if you have a more Arduinistic name for sayQ
@Adrian - glad you like Talkie - can you confirm my GitHub works on your Teensy_LC? It'll be fun - you can start up random sounds/verbiage while having the T_LC busy doing something else.
 
Last edited:
sure, I'll give it a crack ... non-blocking sounds like a great idea .... send some midi messages to the lc to choose 'what is said', display it on a screen, and hear it all as well.... ??
 
defragster ... Works fine on my current example ! I'll check out the non-blockingness of it later ... could I ask, at a high level, how and what your use of interrupts and timers achieves non-blocking wise .... what is blocking vs non-blocking anyway....?? I don't quite get the issue .... I guess the way that Talkie was before your work meant there were no free resources for other things ... so, are you, like, allowing use of the time in between data assemblies / synthesis and in between analog writes??

I attach a zip of my illegal cassette mp3.
 

Attachments

  • teensy2.zip
    879 KB · Views: 184
I tried Talkie on my 3.2 with the prop shield, and I didn't hear anything. I think it should set pin 5 HIGH so the amplifier is enabled. A secondary question is whether there should be some way to use the audio adapter instead of the DAC.

Or perhaps having an example that sets pin 5 high rather than modifying Talkie.cpp.
 
From my working GitHub sketches I've been doing this on Prop Shield - speaker on the USB / AMP end in '+'/'-':

Code:
void setup() {
  Serial.begin(9600);
  pinMode(5, OUTPUT);
  digitalWrite(5, 1);//Enable Amplified.
  while (!Serial && 5000 > millis());
  Serial.println("Setting up");
  analogReference(INTERNAL);  // drop volume level
}
 
Last edited:
defragster ... Works fine on my current example ! I'll check out the non-blockingness of it later ... could I ask, at a high level, how and what your use of interrupts and timers achieves non-blocking wise .... what is blocking vs non-blocking anyway....?? I don't quite get the issue .... I guess the way that Talkie was before your work meant there were no free resources for other things ... so, are you, like, allowing use of the time in between data assemblies / synthesis and in between analog writes??

Thanks for testing on T_LC! If you read between the lines this might be high level . . .

The starting Talkie code had a delay(25) embedded in the code in a while loop. It would setup the synthesis and a timer interrupt. Then the while(){ ...delay(25)} would cycle the loop to decode the needed next set of PWM data for the interrupt code.

Net effect - when voice.say() was called it would return after all data had been decoded and sent to the audio system - this is 'blocking'.

My first trial of concept was to set up the sound and leave and then with a sketch timer at 25000 microseconds to do the data decode - that worked, but put the burden in the sketch. Also used Timer1 object.

With a note from Paul I decided to clean those things up - the PWM interrupt is 125 microseconds - so once in each 200 iterations I had that interrupt internally execute the decode process.

Net effect - when voice.sayQ() is called it returns immediately after pointer to data is stored. The interrupt system parses the data and sends to the audio system - this is 'non-blocking'. To tell when the sound is complete you call voice.active() and wait for it to return 0 - [or ignore it and do whatever you want while the sound plays].

That is the current state of things - working on T_3.2 and T_LC. You didn't use the voice.sayQ yet - but when I did the code change the old style while(){ ...delay(25)} code was gone. So when I restored that it was using the new internal 200 to 1 interrupt process noted above - and then sitting in a while(){voice.active()} loop internally rather than return to user code as voice.sayQ() does.

In fact writing that told me to literally make the code look like this - where sayQ() returns immediately - but say() does not return until the sound is complete:
Code:
void Talkie::say(const uint8_t * addr) {
	sayQ( addr );
	while ( active() );
}
 
Last edited:
Thanks for that ... I get the technique I think (I think I might have even used it myself!) ....

you have broken up the decoding and the audio system...

create the audio data pointer (using "sayQ" ....but not on/in an interrupt per se, rather after a set number of dac interrupts?).... return straight away from "sayQ" (not back to the audio system) .... drive the audio system using the data, using an interrupt timer thingy like for DDS ... so there is space inbetween decodes and in between the audio interrupts ...

its like data delivered on time, rather than staying in the warehouse with the data...

the "active" method ... is to know when the data has spooled through the audio system.

I take it your code change above ensures that the "say" method is blocking??!! you stay in 'say' until the voice is inactive. So no space in between audio interrupts, until the data has spooled through .... Would it not be better to just replace the "say" method entirely with "sayQ"?

I will try out "sayQ" tonight
 
...
I take it your code change above ensures that the "say" method is blocking??!! you stay in 'say' until the voice is inactive. So no space in between audio interrupts, until the data has spooled through .... Would it not be better to just replace the "say" method entirely with "sayQ"? ...

See page 1 this thread - and notes this page about the problem with taking away old say functionality - as noted - it would not run the acorn example as it uses the blocking to stage the audio.

So that note was specifically about restoring the blocking behavior to say, and making the new sayQ interface.

This Talkie code is old and untouched in a few years - on a slower 8bit system it probably wasn't going to work well doing what I did - but it works on Teensy without sitting behind a delay() as it was implemented.
 
Ah got you ... I was being a bit thick ... a quick re-read and now I get it. My acorn example is not going to work with sayQ ... I don't quite get why (staging .?.), but rather than pester you I will read things a bit more carefully code wise etc .....

I will try sayQ on my teensy with my example, and with others ....

the acorn voice is the best voice ..... Waaaahhhh!
 
The Acorn sketch will work - just not as written - if you look at my example for DANGER DANGER it shows putting the addresses into an array and then when one finishes, you push out another one. That sample shows say and sayQ both being used. 'say' freezes the loop while the speech emits - and 'sayQ' shows the loop is processing as it sounds off.

As soon as I get to write a simple bit of code - the sayQ will work on Acorn for 16 items or so in a group - I am going to basically include this 'array' behavior into sayQ.
 
The QUEUED sayQ code it working - first time it compiled - except there is a bit of noise between pulling SOME queued messages!?

Put the sound to a headphone speaker so it is much quieter (with a pot too) and better than my cheap speaker - this makes glitches more audible - I'll have to try the original library with headphones, I may have introduced the noise long ago.

I put in a queue depth of 24 (cost 100 bytes of RAM) - that lets the voltmeter print two full numbers ahead of the one being read, that isn't real useful - except to show the queue is working as there is no delay in the reading so it keeps the queue full..

Modified the other example that announces each second - in setup I jam the queue with 36 items, after going FULL, it BLOCKS so if you get ahead of it nothing is lost and you don't need to check the return each time - then the loop starts and only announces one per second so the queue empties in a few seconds, and then when every the 5th second hits I jam in 12 items, that again empties in following seconds and the gets ahead before the next jamming - handy enough the items being read are numbers so you can hear there are no misses or duplicates!

Now I just need to see about leaving a blank 125 microsecond space between starting each queued object or something - though the audible noise is RARE - it may just be some samples? Would be good to see it on a scope to see if there is more noise than I can hear.

Has been running these spastic test cases for over 30 minutes with no problem - just the rare and SHORT - but consistent when it happens? - chirp/squeak/squeal/hum?
 
A lot of the samples are noisy, without your modifications, on my system. I get all sorts of noise from the teensy lc setup (I have a pretty good audio setup)

I'm keen to get back to this. So i will report on sound quality comparison soon. thankyou for all your work.

I had already set up an array of addresses, as part of my plan to use an external numbered signal to trigger a sample!

But ...at the moment I have all of the 'says' one after another, in one loop ... as you write, using an array of addresses will allow one sample per loop / function call. I have been exceptionally busy the last coupple of days, and its not looking like letting up over the weekedn, so fingers crossed for a snatched hour of talkie.
 
Opps - didn't get to posting my code yet today . . . was going to make the samples to HEX for comparison and didn't get that far . . . after dinner . . .
 
Okay - My GitHub code is UPDATED:: https://github.com/Defragster/Talkie

You can voice.say() and block on each sound as before, or voice.sayQ() and as long as there is queue space return immediately. You can check voice.active() to see when sound is off. I didn't add a way to dump the queue and end the sound, that might be good and would be trivial. You can voice.sayQ and put in 1-24 elements and then do voice.say() to block until they complete - like in the _2_Voltmeter example I just updated - that also prints the open queue size up front.

I've done side by side old and new and in headphones - professionally wired with two bits of CAT5 to the jack plug - the sounds my crummy overdriven speaker was 'filtering' hid some stuff - the digit 8 in one has a recurring 'blip' on either old or 'NEW' library.

In taking out the delay(25) what I did was make a one in 200 ( ISR_RATIO ) callout from the existing timerInterrupt(). This happens in the new library whether the .say() or sayQ() interface is used. So playing the 2 minute "Demo_Toms_Diner" on two side by side would catch any off by one errors in my math every 125usecs or each 25msec - and they should not stay in sync with errors (that would take two Prop Teensy's and a pushbutton to synchronize a start). I don't hear that though - there are 'artifacts' in both versions. I would not have been surprised that taking out the interruptible delay(25) would introduce something - but sharing one timer that can't be helped as certainly one 125usec interval is skipped for an update in doing all that code. I did all my work at 96MHz_OC - I just dropped to 24MHz and I'm not sure it is any worse - a scope would see those 25msec periods if they interfere? A fix would be to watch time in the sayisr() code and call out to the PWM updates in timerInterrupt() - or a second timer ...

I just tried this rather than cascading within the one timer and the same artifacts are present at 24MHz - I never tried the original code at 24MHz - the artifacts are minor things I half expect to be there.
Code:
		IntervalTimer *t2 = new IntervalTimer();
		t2->begin(sayisr, 25000);
		t2->priority(200);

As long as this is added to setup in some fashion any existing Example works on the new library to come out the PropS' Amp. Note the conditional while(!Serial) seems critical as a sound app is likely to run on batteries without USB. - though 5 second delay is extreme I found.
Code:
  // analogReference(INTERNAL);  // drop volume level :: OPTIONAL
  while (!Serial && 5000 > millis());
  Serial.println("\nSetting up");
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(5, OUTPUT);
  digitalWrite(5, 1);//Enable Amplified.

<EDIT>: I found one small issue (avoid a few instructions) at the end of "timerInterrupt()" :: This INC++ should be conditioned "if ( o->ptrAddr ) nextData++;"
That came to me as I was implementing the sayQ( 0 ); to EMPTY the queue and stop the sound. That appears to be working, I think sound abort could be as useful as noTone(), especially with a queued playlist.
Paul - if you glance at it (in advance) and see anything obvious/anti_Arduino'ish that I might fix - let me know.

<EDIT>: Of course the sayQ( 0 ) could be given an added method like noTone(), if I had a name for it.
 
Last edited:
FWIW, I'm planning to work on Talkie after we get the Prop Shield fully released.

Paul - I've spent time with this and seen it work quite well. (a minor squeak/chirp) in a sentence full of syllables - usually on the same 'syllable'. Not sure of your timeline on 1.28 - If you dropped it in 1.28 I think it could get used effectively. Of course I've only used it w/my Beta Prop Shield - but how the sound is heard shouldn't change that if it makes good signals. I even shrink wrapped wires to an SMD headphone jack for stability.

Ideally it would be cool if my updated version were the included version - blocking is really prohibitive - so if you reviewed it for a few minutes for any changes/extensions I'd be happy to make them and a pull request - as to names of other elements that wouldn't be able to be changed once released.

<edit> @Adrian or anyone - have you worked with the Updated Talkie any more?

New change on github with the sayQ(0) and the minor cleanup noted. I added two 25 sec phone recordings of my headphones - you can hear the 'worst' of the stuff I heard a couple times. Both on T_3.2 at 24 MHz one is the original 'old' code and the second is the new TQ code. Both seem to have similar issues AFAIK.
 
Last edited:
EDIT: I 'included' Arduino.h in the Talkie.h file and it compiled cleanly ... weird ... I am using arduino 1.6.1 ide and an old version of teensyduino...could that be it?

I got a compile error 'byte does not name a type'!!! the same example compiled with your previous iteration.

Code:
In file included from TALKIEACORN.ino:13:0:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Talkie/Talkie.h:27:2: error: 'byte' does not name a type
  byte head; // init on setup = 0
  ^
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Talkie/Talkie.h:28:2: error: 'byte' does not name a type
  byte tail; // init on setup = 0
  ^
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Talkie/Talkie.h:29:2: error: 'byte' does not name a type
  byte free; // init on setup = SAY_BUFFER_SIZE
  ^
Error compiling.
 
Last edited:
Yes, it's the IDE. An IDE change preceding 1.6.8 was to by default include "needed" HEADERS when they could be determined without hassling folks.

I've ended up going to the latest as they evolve by the time PJRC releases each new TeensyDuinoInstall for them (and often all of his beta's from day 1)- starting with 1.6.0 when I got here 13 months back. I do however use unzip installs so I can always still run the prior version for testing or in case of breakage.

Let me know if you find anything else. I enjoyed working with the Talkie code and would like to see it good enough to be included - or at least the basis for an improved non-blocking version. Do you have any feedback on the sound quality versus the Stock version or by any chance run it on a slower AVR Arduino system?
 
Last edited:
Hi

I converted my Acorn example as per your instructions. I added an array interface... so you send an array 1,4,5,7,3,5 to your sayQ function ...the numbers represent samples, and you spool the array through sayQ. Anyway, your sayQ version works flawlessly. The same noise /artefacts I get from the standard version I get from yours.....!!! So the quality is the same. The artefacts are the real character of this program in my view. It is just sooo cool . I never trusted HAL ... he was such a smooth talking bastard.

I really like yr first voltmeter example ... numbers to syllables is quite a challenge, and the 'AND's are really neat ....thank you.

Here is my code..

Code:
// Talkie library
// Copyright 2011 Peter Knight
// This code is released under GPLv2 license.
//
// The following phrases are derived from those built into the
// Acorn Computers Speech Synthesiser add-on from 1983.
//
// A male voice with an RP English accent, voiced by Kenneth Kendall.
//
// Due to the large vocabulary, this file takes up 16Kbytes of flash.
// To save space, just copy and paste the words you need.

#define ACORN
#include <Talkie.h>

#ifdef ACORN
const uint8_t spPAUSE1[]    PROGMEM = {0x08, 0x14, 0xC1, 0xDD, 0x45, 0x64, 0x03, 0x00, 0xFC, 0x4A, 0x56, 0x26, 0x3A, 0x06, 0x0A};
const uint8_t spPAUSE2[]    PROGMEM = {0x08, 0x14, 0xC1, 0xDD, 0x45, 0x64, 0x03, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x4A, 0x46, 0x51, 0x39, 0x79, 0x15, 0x0A};
const uint8_t spTONE1[]     PROGMEM = {0x8D, 0xF2, 0xDE, 0xDD, 0xDD, 0x93, 0x74, 0xAA, 0x53, 0x9D, 0xEA, 0x54, 0xA7, 0x3A, 0xD5, 0xA9, 0x4E, 0x75, 0xAA, 0x53, 0x9D, 0xEA, 0x54, 0xA7, 0x3A, 0xD5, 0xA9, 0x4E, 0x75, 0xAA, 0x53, 0x9D, 0xEA, 0x54, 0xA7, 0x3A, 0xD5, 0xA9, 0x4E, 0x75, 0xAA, 0x53, 0x9D, 0xEA, 0x54, 0xA7, 0x3A, 0xD5, 0xA9, 0x4E, 0x75, 0xAA, 0x53, 0x9D, 0xFA, 0x4A, 0x26, 0x51, 0x39, 0x79, 0x15, 0x0A};
const uint8_t spTONE2[]     PROGMEM = {0x4D, 0xF1, 0xDE, 0xDD, 0xDD, 0x93, 0x74, 0xA5, 0x2B, 0x5D, 0xE9, 0x4A, 0x57, 0xBA, 0xD2, 0x95, 0xAE, 0x74, 0xA5, 0x2B, 0x5D, 0xE9, 0x4A, 0x57, 0xBA, 0xD2, 0x95, 0xAE, 0x74, 0xA5, 0x2B, 0x5D, 0xE9, 0x4A, 0x57, 0xBA, 0xD2, 0x95, 0xAE, 0x74, 0xA5, 0x2B, 0x5D, 0xE9, 0x4A, 0x57, 0xBA, 0xD2, 0x95, 0xAE, 0x74, 0xA5, 0x2B, 0x5D, 0xF9, 0x11, 0x5A};
const uint8_t spTHREE[]     PROGMEM = {0x08, 0xA8, 0xC2, 0x8C, 0x02, 0x04, 0x68, 0x2A, 0xDC, 0xF9, 0x51, 0x5B, 0x96, 0x79, 0x8D, 0x10, 0xE5, 0xCA, 0x2E, 0x9A, 0x76, 0x72, 0xD0, 0xC2, 0x5C, 0x25, 0x21, 0x23, 0xCD, 0x0C, 0x4F, 0xD4, 0x22, 0x7A, 0x46, 0x34, 0x3E, 0xF1, 0x48, 0x86, 0xD2, 0xB1, 0xEA, 0x24, 0x33, 0x16, 0x62, 0xE7, 0xAA, 0x55, 0xAC, 0xD4, 0x04, 0xD5, 0x8D, 0x47, 0xB3, 0x53, 0x33, 0xE4, 0x2C, 0x69, 0xED, 0x4E, 0x81, 0x30, 0x53, 0xA7, 0xF5, 0xBB, 0x14, 0x43, 0xF4, 0x92, 0x36, 0xEC, 0x92, 0x04, 0xD5, 0x4B, 0xD2, 0xB8, 0xAB, 0x23, 0xF4, 0x34, 0xCE, 0x63, 0x19, 0x57, 0x73, 0x84, 0xAE, 0x26, 0x69, 0x9C, 0x8D, 0xC0, 0xAB, 0x6B, 0x87, 0xB1, 0x7B, 0x94, 0x99, 0x8A, 0xF2, 0x5A, 0x66};
const uint8_t spEIGH_[]     PROGMEM = {0x23, 0x1E, 0xC5, 0x58, 0x33, 0xA7, 0x9E, 0xA0, 0x6A, 0xF1, 0xAD, 0x9E, 0xB2, 0xE2, 0xEE, 0x49, 0xAB, 0x3A, 0xCA, 0x2A, 0x66, 0x72, 0x94, 0xE9, 0xDA, 0xBB, 0x0A, 0xC3, 0x30, 0x8C, 0xB5, 0x1D, 0x5B, 0x4C, 0x42, 0xB9, 0xBB, 0x88, 0x6C, 0x00, 0x80, 0xFF, 0x4E};
const uint8_t spNINE_[]     PROGMEM = {0xA1, 0x4A, 0x4C, 0xF4, 0x31, 0xDD, 0x85, 0x32, 0x71, 0xB6, 0xC7, 0x74, 0x57, 0xF2, 0x4C, 0x4D, 0x1F, 0x33, 0x79, 0xCB, 0x1A, 0x48, 0x3E, 0xD6, 0xFA, 0x27, 0xE9, 0xB2, 0xD5, 0xC4, 0x1B, 0x9D, 0xB8, 0xD9, 0x4B, 0x17, 0x4F, 0x74, 0xD2, 0xAE, 0x6E, 0x42, 0x3C, 0xD1, 0x29, 0xA7, 0xE9, 0xAA, 0x90, 0x54, 0xA7, 0x9A, 0xBE, 0x3D, 0x52, 0x5A, 0x9D, 0x66, 0xC5, 0x51, 0x49, 0x6B, 0x74, 0xDA, 0x95, 0x46, 0x30, 0xA2, 0xD1, 0xE8, 0x66, 0x2E, 0xE4, 0xCA, 0xCA, 0x6D, 0x58, 0x21, 0x89, 0x3A, 0x23, 0x87, 0x21, 0x73, 0xB5, 0x71, 0x4D, 0x6A, 0x86, 0x20, 0x2C, 0xCE, 0xCD, 0xC9, 0xFF, 0x41};
const uint8_t spACORN[]     PROGMEM = {0x23, 0x9B, 0x35, 0x85, 0xD3, 0x96, 0x9C, 0x64, 0xD6, 0x12, 0x0A, 0x5F, 0x7C, 0xA2, 0x95, 0xD6, 0x30, 0x6C, 0xF1, 0x89, 0x56, 0x18, 0x86, 0xCC, 0x45, 0x2B, 0x5A, 0xA1, 0x11, 0x2B, 0x1B, 0xB7, 0x68, 0x34, 0x06, 0xCF, 0x9E, 0x94, 0xB2, 0x91, 0x19, 0x32, 0xAB, 0x96, 0x2A, 0x84, 0x72, 0x77, 0x11, 0xD9, 0x00, 0x0A, 0x08, 0x51, 0xC9, 0x02, 0x25, 0x8F, 0x6D, 0x54, 0x4D, 0x66, 0xB6, 0x22, 0x86, 0x09, 0x33, 0xDA, 0xD5, 0xDA, 0xE8, 0x2A, 0xD3, 0xB0, 0x4F, 0xEB, 0x92, 0xA9, 0xCA, 0xA0, 0xBC, 0x6D, 0x48, 0xA6, 0x2A, 0x83, 0xF2, 0x95, 0x29, 0xD9, 0xEC, 0x34, 0xEC, 0x9B, 0xE6, 0x90, 0xAA, 0x5D, 0x78, 0x73, 0x98, 0x63, 0xC9, 0x74, 0xD6, 0x57, 0x6E, 0x8E, 0xCB, 0x42, 0x6C, 0x66, 0xB9, 0x29, 0x0D, 0x4B, 0xE6, 0x8E, 0x1B, 0xC6, 0x94, 0x2C, 0x84, 0xA2, 0x73, 0x98, 0xB2, 0x71, 0x0B, 0xF0, 0xCC, 0x6E, 0x4E, 0x3A, 0xD4, 0xD8, 0xB3, 0xAA, 0xB9, 0x68, 0x33, 0x23, 0xD5, 0xF2, 0x25, 0x51, 0x15, 0x31, 0x41};
const uint8_t spCASSETTE[]  PROGMEM = {0x06, 0x68, 0x86, 0x65, 0x84, 0x55, 0x8B, 0x74, 0xB9, 0xAD, 0x13, 0xB5, 0xEC, 0x1A, 0x16, 0x8D, 0x4F, 0xD6, 0xC3, 0x68, 0x98, 0xB4, 0x3A, 0x79, 0x77, 0xA5, 0x69, 0xB6, 0xBA, 0x14, 0xD5, 0xAB, 0xB9, 0x75, 0x29, 0x04, 0x2C, 0xA4, 0x86, 0x80, 0x83, 0x23, 0x10, 0x70, 0x99, 0x3B, 0x03, 0x3E, 0xCB, 0x64, 0xC0, 0x67, 0x91, 0x02, 0xB8, 0x2A, 0x42, 0x01, 0x4B, 0x95, 0x2D, 0xB7, 0x59, 0x97, 0xD2, 0x58, 0x7C, 0xA2, 0xEE, 0x52, 0xC2, 0x7D, 0xF1, 0xC9, 0xBA, 0x2F, 0x09, 0xB7, 0xD5, 0xA7, 0xEA, 0x3E, 0x25, 0xDC, 0x57, 0xA7, 0xA6, 0x19, 0x93, 0x8A, 0x98, 0x89, 0x1A, 0xA1, 0xDC, 0x5D, 0x44, 0x36, 0x80, 0x00, 0xAE, 0x48, 0x93, 0x00, 0x02, 0xAA, 0x6F, 0xF8, 0x25, 0x51, 0x15, 0x61, 0x41, 0x25, 0x41, 0x09, 0x61};
const uint8_t spCOMPUTER[]  PROGMEM = {0x06, 0x28, 0x29, 0x68, 0x44, 0x29, 0xAA, 0xA6, 0xD6, 0xEC, 0x15, 0xE7, 0x9C, 0xE6, 0x64, 0xAB, 0x5A, 0x9E, 0xBD, 0x96, 0x41, 0xB6, 0x0D, 0x79, 0xB2, 0xDC, 0x48, 0xDD, 0xCD, 0x94, 0x49, 0x53, 0x15, 0x7B, 0x12, 0x54, 0x09, 0xE5, 0xEE, 0x22, 0xB2, 0x81, 0x01, 0xD5, 0x86, 0x97, 0xA0, 0x47, 0x22, 0xCF, 0xAA, 0xDC, 0xFC, 0x26, 0x8D, 0xB2, 0x7D, 0xF5, 0xF2, 0x33, 0x6D, 0xCD, 0xB0, 0xD7, 0x3B, 0xE8, 0x11, 0x2A, 0x84, 0x72, 0x77, 0x11, 0xD9, 0xA0, 0x80, 0x6D, 0x35, 0x1D, 0xB0, 0x89, 0xFB, 0x48, 0x8A, 0x35, 0x75, 0xED, 0xDA, 0xAB, 0xAA, 0xDE, 0x2D, 0x24, 0x57, 0xAF, 0xB6, 0xF9, 0xB6, 0x14, 0x5D, 0x5D, 0xA6, 0x52, 0xD3, 0x5C, 0x73, 0xB6, 0xDB, 0xB3, 0x4F, 0x4F, 0x89, 0x31, 0xFF, 0x15, 0x61, 0x51, 0x25, 0x25, 0x79, 0x61};
const uint8_t spFILE[]      PROGMEM = {0x08, 0xE8, 0xD2, 0x95, 0x00, 0x4D, 0xA7, 0x09, 0xA0, 0xC8, 0xF0, 0xE6, 0xE5, 0x54, 0x9E, 0x4A, 0x8F, 0x4E, 0x50, 0xFC, 0x95, 0xB9, 0x36, 0xB8, 0xE1, 0x89, 0xAA, 0xB9, 0x52, 0xF3, 0x86, 0x27, 0x6E, 0xFA, 0xDA, 0xCD, 0x5A, 0x9E, 0xB4, 0xEA, 0x6B, 0x77, 0x6B, 0x79, 0x8A, 0xA6, 0xB7, 0x32, 0xA4, 0xD3, 0xA9, 0xBA, 0xDD, 0xC8, 0x94, 0x55, 0xA7, 0xEB, 0xA1, 0x3D, 0x83, 0x17, 0x9F, 0xBE, 0x87, 0x90, 0x08, 0x5B, 0x3C, 0x86, 0xEE, 0x4C, 0xB2, 0x6C, 0x71, 0x99, 0x8A, 0x97, 0x48, 0xAF, 0xD9, 0x61, 0xCE, 0x4E, 0x2B, 0xB4, 0xE6, 0x84, 0x25, 0x79, 0xCF, 0x22, 0x5F, 0xED, 0x67, 0x33, 0x85, 0xEE, 0x66, 0xD2, 0x8D, 0xDD, 0x18, 0x62, 0x64, 0x52, 0xAC, 0xB2, 0xE3, 0xFF, 0x15, 0x65, 0x25, 0x49, 0x31};
const uint8_t spFROM[]      PROGMEM = {0x08, 0xE8, 0xDA, 0x84, 0x02, 0x0A, 0x68, 0x26, 0x54, 0x03, 0xAE, 0x88, 0x83, 0x2A, 0xC4, 0x73, 0x97, 0x2A, 0x2D, 0x8D, 0x90, 0xC8, 0xBD, 0xEA, 0x1C, 0xAD, 0x22, 0xA8, 0xF7, 0x69, 0xB2, 0xAF, 0x8A, 0xA4, 0x3E, 0xA7, 0xCD, 0xBE, 0x2A, 0x12, 0xF7, 0x9C, 0x2E, 0x9B, 0x6D, 0x0B, 0xEA, 0x72, 0xFA, 0x6C, 0x6E, 0x34, 0xB8, 0xF5, 0xEA, 0xB3, 0xBE, 0xB5, 0xE0, 0xD6, 0xA3, 0xCF, 0x7A, 0x5A, 0x43, 0x3D, 0xB7, 0x2E, 0xAB, 0xB6, 0x14, 0x52, 0x5D, 0xDA, 0x24, 0x5A, 0x43, 0x58, 0x4B, 0x6E, 0x43, 0x13, 0x9D, 0x85, 0x91, 0xB6, 0xF1, 0xCD, 0xFF, 0x71};
const uint8_t spILLEGAL[]   PROGMEM = {0x25, 0x19, 0x4C, 0xA9, 0x6F, 0x42, 0xF7, 0x2C, 0x67, 0x21, 0x5F, 0x20, 0x38, 0xC3, 0x1E, 0x96, 0xE4, 0x70, 0x65, 0x4B, 0x5F, 0xDD, 0xA2, 0x43, 0x85, 0xAD, 0xA2, 0xF5, 0x08, 0xB6, 0x36, 0xD0, 0xD6, 0x26, 0x2B, 0x9A, 0xD6, 0x40, 0xBB, 0xAA, 0xAC, 0x64, 0x79, 0x03, 0xDD, 0xAE, 0x3D, 0xB2, 0x99, 0x08, 0x6A, 0xBA, 0x72, 0xA9, 0x56, 0x37, 0xE0, 0xE9, 0x46, 0xA6, 0x5A, 0xDD, 0x81, 0xAA, 0x67, 0x21, 0x50, 0x04, 0x77, 0x11, 0x91, 0x0D, 0xAE, 0x28, 0xA9, 0xC1, 0xD4, 0x6C, 0x97, 0x36, 0xC7, 0x46, 0xF7, 0x48, 0x34, 0xFA, 0xAA, 0xC3, 0x4A, 0x7D, 0xF1, 0x18, 0xB2, 0x8F, 0x0C, 0xCE, 0x35, 0x65, 0x8A, 0xB1, 0xDC, 0x39, 0x5B, 0x87, 0x39, 0x94, 0x72, 0xE3, 0x5E, 0x1C, 0xA6, 0x10, 0xDB, 0x83, 0xB2, 0xAB, 0x1B, 0xA3, 0x1B, 0x6B, 0xB4, 0xB5, 0x7E, 0xF8, 0x5A, 0x39, 0x49};
const uint8_t spIS[]        PROGMEM = {0xC9, 0x5F, 0x3E, 0x90, 0xB2, 0x17, 0xDF, 0xE0, 0x04, 0xDB, 0x04, 0x72, 0xF5, 0xA2, 0x13, 0x6E, 0x1D, 0xC8, 0xD5, 0x8B, 0x4E, 0xB4, 0x5C, 0x23, 0x65, 0x2F, 0x3A, 0xE9, 0x76, 0x85, 0x1C, 0xB5, 0xE8, 0x94, 0x33, 0x24, 0x89, 0xD6, 0xA2, 0xD5, 0xCD, 0xD4, 0x24, 0x54, 0x8B, 0xC6, 0xD8, 0x0D, 0x4B, 0xF8, 0xD6, 0x29, 0x63, 0xE2, 0x6E, 0x9D, 0x1D, 0x3B, 0x8F, 0x66, 0x3C, 0xD0, 0xCD, 0xA3, 0x12, 0xDA, 0x89, 0x01, 0x13, 0xB0, 0x23, 0xE0, 0x61, 0x76, 0x04, 0x7C, 0x4A, 0xFA, 0x29};
const uint8_t spNEGATIVE[]  PROGMEM = {0x26, 0x2E, 0x4C, 0x24, 0xCC, 0x13, 0xC5, 0x32, 0x14, 0x49, 0xD0, 0x9C, 0xA4, 0x9B, 0x92, 0x25, 0xC9, 0x33, 0x9C, 0x6E, 0x46, 0x32, 0x94, 0x91, 0x7B, 0x2C, 0x3E, 0xD1, 0x74, 0x21, 0x6E, 0xD1, 0xF8, 0x84, 0xCB, 0x26, 0x9B, 0x7B, 0xE3, 0x13, 0x4C, 0x93, 0xE8, 0x9D, 0xAB, 0x46, 0x30, 0x4A, 0x41, 0x44, 0xCE, 0x22, 0x49, 0xD7, 0x06, 0x16, 0xB5, 0x7A, 0x64, 0xDD, 0x15, 0x87, 0x8A, 0xE2, 0x95, 0x75, 0xA3, 0xD0, 0x13, 0xB5, 0x56, 0xDA, 0x94, 0x70, 0x75, 0xD4, 0x26, 0x9D, 0x50, 0xEE, 0x2E, 0x22, 0x1B, 0x0C, 0xB0, 0xA8, 0x85, 0x03, 0x16, 0x0B, 0x0D, 0xED, 0x16, 0x4E, 0x5A, 0x16, 0xBB, 0xB4, 0xC3, 0x2A, 0xA5, 0x57, 0x9D, 0x32, 0x74, 0x27, 0x1C, 0x59, 0x73, 0xC2, 0xD2, 0x8D, 0x70, 0x65, 0xCE, 0x76, 0x4B, 0x33, 0x22, 0xE5, 0x39, 0xCB, 0x2D, 0xD5, 0x93, 0xA5, 0xD5, 0x2C, 0x33, 0x67, 0x23, 0x5A, 0x5A, 0x35, 0xC5, 0x5C, 0x55, 0x88, 0xA9, 0x35, 0x36, 0xF3, 0x70, 0xA9, 0xA9, 0xAA, 0x98, 0x00, 0x4D, 0x9B, 0xFC, 0x75, 0x51, 0x39};
const uint8_t spNO[]        PROGMEM = {0xAC, 0xEF, 0xCC, 0xD9, 0x25, 0x6C, 0xBB, 0xB6, 0x50, 0xD1, 0xC7, 0x74, 0x17, 0x9A, 0x42, 0xD9, 0x1E, 0xD3, 0x5D, 0xAA, 0x2B, 0x51, 0x7D, 0x2C, 0x77, 0x29, 0xAF, 0xC4, 0xF4, 0x31, 0x93, 0xB7, 0xAC, 0x81, 0xE4, 0x63, 0xAD, 0x7F, 0xD2, 0x2E, 0x5B, 0x4D, 0xBC, 0xD1, 0x89, 0x9B, 0x6E, 0x33, 0xF5, 0x4D, 0x27, 0x6B, 0x26, 0x3D, 0xD8, 0x56, 0x9F, 0xA2, 0xEA, 0x0E, 0x53, 0xDB, 0x74, 0xAA, 0xA6, 0x32, 0x42, 0xE5, 0xD3, 0xEE, 0xC7, 0xD8, 0x44, 0xA7, 0x19, 0x7E, 0x0E, 0x53, 0x32, 0xE3, 0x6C, 0xF6, 0x28, 0x8C, 0xC1, 0xB7, 0x19, 0xE5, 0x9C, 0x38, 0xDA, 0xF1, 0xFF, 0x15, 0x79, 0x39};
const uint8_t spNUMBER[]    PROGMEM = {0xA6, 0x0A, 0x42, 0x72, 0xB9, 0xDC, 0x84, 0x32, 0x0A, 0x89, 0xA3, 0x72, 0x13, 0xF2, 0xC0, 0x35, 0x0E, 0xDB, 0x4D, 0x49, 0x13, 0x57, 0x3D, 0xAA, 0xA4, 0x27, 0xAE, 0xAE, 0xC3, 0x25, 0x12, 0x9F, 0xA8, 0xBA, 0x2D, 0x37, 0x4F, 0x74, 0x82, 0x62, 0xAF, 0xC3, 0x3C, 0xD5, 0xF1, 0x8B, 0xBD, 0x0E, 0xB5, 0x44, 0xCB, 0xAF, 0x72, 0xAD, 0x91, 0xDC, 0xAC, 0xA0, 0xCA, 0xB1, 0x46, 0x4A, 0x33, 0x82, 0x6C, 0x46, 0x03, 0xA4, 0x4B, 0x8A, 0xB2, 0x0C, 0x2B, 0x90, 0x2D, 0x2A, 0x33, 0xD2, 0xB2, 0xC4, 0x3E, 0x8B, 0xCA, 0xCA, 0xD2, 0x10, 0x5F, 0xD5, 0xAA, 0xE2, 0xDB, 0x8C, 0x65, 0x53, 0xAB, 0x73, 0x09, 0x57, 0xAE, 0xDB, 0x6D, 0x28, 0xB1, 0xDC, 0xC5, 0x1F, 0xB7, 0x29, 0x87, 0xF0, 0xD0, 0xBE, 0x94, 0xE7, 0xB0, 0x64, 0x1F, 0x16, 0x5A, 0x53, 0xEC, 0xFA, 0x79};
const uint8_t spPARAMETER[] PROGMEM = {0x04, 0xD0, 0xA2, 0x3D, 0xA5, 0xC5, 0xA7, 0x9B, 0x6B, 0xCD, 0x91, 0xE6, 0x21, 0x85, 0xE3, 0x71, 0x7B, 0xDA, 0xB2, 0x1C, 0xB8, 0x38, 0x3C, 0x6E, 0xCA, 0xD2, 0xC5, 0x32, 0xF5, 0xB6, 0x31, 0x6B, 0x69, 0x39, 0x6C, 0x61, 0xE9, 0x65, 0x45, 0xA5, 0x5B, 0x71, 0x45, 0xA3, 0x13, 0xD4, 0x9C, 0x11, 0x9A, 0x8D, 0x4E, 0xD0, 0xEC, 0x46, 0xBA, 0xD5, 0x5A, 0x49, 0x89, 0x9E, 0x42, 0x39, 0xB9, 0xE4, 0xC9, 0x49, 0x31, 0x74, 0xBB, 0x92, 0x67, 0x23, 0xA5, 0x50, 0xDD, 0x4A, 0x9E, 0x8C, 0xB4, 0x42, 0xAE, 0x3B, 0x65, 0x2D, 0x5E, 0xC6, 0x3E, 0xA5, 0xB5, 0xD5, 0x69, 0x28, 0xC7, 0x62, 0xD2, 0x0A, 0xE5, 0xEE, 0x22, 0xB2, 0x41, 0x01, 0x9B, 0x65, 0x1A, 0xA0, 0xE0, 0xF0, 0xD6, 0x24, 0xEF, 0x96, 0xDA, 0xB5, 0xCE, 0xD0, 0x82, 0x7B, 0xAA, 0xAE, 0x1E, 0x53, 0x4D, 0x15, 0xA1, 0xF2, 0xB8, 0x8D, 0x25, 0x57, 0x84, 0xEA, 0xE2, 0x32, 0x96, 0x9C, 0x11, 0xEC, 0x93, 0xFF, 0x51, 0x61, 0x39, 0x51, 0x05};
const uint8_t spPROGRAMME[] PROGMEM = {0x0C, 0x48, 0x2E, 0x95, 0x03, 0x2E, 0x0A, 0x8D, 0x3D, 0xDA, 0x13, 0xD5, 0x68, 0xF9, 0xA9, 0x73, 0x68, 0xC7, 0x94, 0x13, 0x94, 0x62, 0xA9, 0xC6, 0xAB, 0x4F, 0x50, 0x63, 0x84, 0x19, 0xAD, 0x3E, 0x41, 0x0B, 0xEE, 0x6E, 0xB8, 0xE9, 0x04, 0xD5, 0x69, 0x84, 0xF0, 0xAB, 0x11, 0x66, 0xE7, 0x66, 0x22, 0xAF, 0x5C, 0x14, 0xA3, 0x2B, 0xAB, 0x2E, 0x34, 0xA9, 0x54, 0x19, 0x1D, 0x96, 0x4A, 0xE5, 0x3E, 0xAB, 0xB8, 0x44, 0x9C, 0x50, 0xA7, 0x66, 0x21, 0xA4, 0x71, 0x52, 0x95, 0x33, 0x17, 0x66, 0xA7, 0x1D, 0x75, 0x69, 0x1A, 0x94, 0xE9, 0x75, 0xB5, 0xA5, 0xA9, 0x9B, 0xE7, 0x9A, 0x33, 0xB4, 0xD8, 0xE1, 0xC1, 0x5D, 0xCE, 0xD8, 0xFC, 0x44, 0x24, 0x75, 0x3E, 0x53, 0x8B, 0xE5, 0x19, 0xBC, 0x78, 0xCC, 0x35, 0x76, 0x64, 0xF2, 0xED, 0x36, 0xD7, 0x54, 0x51, 0xCE, 0xB3, 0xEB, 0x1C, 0xE6, 0xEC, 0x34, 0x0C, 0xAC, 0x89, 0x9F, 0xED, 0xF2, 0x45};
const uint8_t spTHIS[]      PROGMEM = {0xAA, 0xF2, 0xD2, 0x6C, 0xA4, 0x2A, 0xAA, 0xCA, 0x4B, 0xB5, 0xB6, 0x6C, 0x18, 0xCA, 0xAA, 0x94, 0x53, 0xB4, 0xF1, 0x8A, 0x3B, 0x0B, 0xEC, 0xD2, 0x45, 0x27, 0xEC, 0xDC, 0x71, 0xCA, 0x67, 0x9D, 0x68, 0x48, 0xC7, 0xE9, 0x58, 0x74, 0xD2, 0x69, 0x13, 0x22, 0x63, 0xF1, 0xA9, 0x86, 0x35, 0xEC, 0xCC, 0xC5, 0xAD, 0xEE, 0x5E, 0x68, 0xE4, 0xE2, 0x2A, 0x20, 0xE3, 0x10, 0x01, 0x2C, 0x62, 0x66, 0x80, 0xC7, 0xDC, 0x15, 0xF0, 0x98, 0x94, 0x00, 0x3E, 0xB7, 0x10, 0xC0, 0xA3, 0x96, 0x0C, 0xF8, 0x42, 0x9D, 0x01, 0xDF, 0x09, 0x33, 0xE0, 0x1B, 0x31, 0x02, 0x7C, 0xA7, 0x42, 0x80, 0x6F, 0x94, 0x10, 0xF0, 0x95, 0x39, 0x02, 0x1A, 0x0E, 0xFD, 0x51, 0x59, 0x49, 0x15};
const uint8_t spYOUR[]      PROGMEM = {0xA1, 0x69, 0x86, 0xD1, 0xA7, 0x2B, 0xE5, 0x3A, 0x55, 0x2D, 0x08, 0xDA, 0xC4, 0xCA, 0x56, 0x16, 0xA9, 0x5C, 0xA3, 0x3D, 0x4F, 0x99, 0x44, 0x59, 0x85, 0xF4, 0x5A, 0x65, 0x74, 0xE3, 0xA9, 0xDC, 0xFB, 0x96, 0xA7, 0x4A, 0x7A, 0xA2, 0x8C, 0x72, 0x9F, 0x2A, 0xDA, 0xC9, 0x54, 0xCE, 0xBD, 0xEA, 0x10, 0x26, 0x42, 0xB4, 0xF7, 0xAA, 0xA3, 0xDF, 0x08, 0xD1, 0xDE, 0xA3, 0x8E, 0x6E, 0x23, 0x44, 0x73, 0x8F, 0x3A, 0x9A, 0x8D, 0x54, 0xC9, 0x35, 0xEA, 0xE4, 0xBA, 0xD2, 0xB0, 0xF7, 0x68, 0x92, 0xDF, 0x74, 0x91, 0x9C, 0xA5, 0x89, 0xBD, 0xD3, 0x48, 0x3B, 0xF8, 0xF6, 0xFF, 0x2D};
const uint8_t * indexArray [] {spTHIS, spIS, spNO, spNEGATIVE, spPARAMETER, spPROGRAMME, spNUMBER, spILLEGAL, spCASSETTE, spPAUSE1, spPAUSE2};
#endif

Talkie voice;

void setup() {
}
void loop() {
  int wordarray[] {0, 1, 2, 3, 6, 9, 0, 1, 2, 3, 4, 9, 7, 8, 10, 7, 8, 10};
  int wordarraysize = sizeof (wordarray) / 4;
  arrayInterface (wordarray, wordarraysize);
  //delay (20);
}

void arrayInterface (int * wordArray, int wordArraySize) {
  for (uint8_t i = 0; i < wordArraySize; i++) {
    voice.sayQ (indexArray[wordArray[i]]);
  }
}
 
COOL - IT WORKS !!!! 'This is no negative number this is no negative parameter illegal cassette illegal cassette ...'

I ran your sketch - without the setup code it is oddly silent on my Prop board! I brought back my qBlink() so the pauses in the speech queue show up and a long loop delay to let queue empty and show it is indeed playing from recorded list even while in delay() that lets queue play down - as shown by printed queue empty state.
Code:
#define qBlink() (digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ))
void setup() {
  while (!Serial && 5000 > millis());
  Serial.println("\nSetting up");
  pinMode(LED_BUILTIN, OUTPUT);
  qBlink();
  pinMode(5, OUTPUT);
  digitalWrite(5, 1);//Enable Amplified PROP shield
}

int wordarray[] {0, 1, 2, 3, 6, 9, 0, 1, 2, 3, 4, 9, 7, 8, 10, 7, 8, 10};
int wordarraysize = sizeof (wordarray) / 4;
void loop() {
  arrayInterface (wordarray, wordarraysize);
  delay (3000);
  qBlink();
}

void arrayInterface (int * wordArray, int wordArraySize) {
  for (uint8_t i = 0; i < wordArraySize; i++) {
    qBlink();
    Serial.println( voice.sayQ (indexArray[wordArray[i]]) );
  }
}

I made PULL request so you can own the non-blocking Talkie edits with sound queue I made. Perhaps one of the samples is worth taking/building on - to demonstrate usage - but not all.

Edits to Talkie.cpp and .h first 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 for playing sequentially without user attention or delay.

.active() - is TRUE when sounds are playing
.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
 
Last edited:
Status
Not open for further replies.
Back
Top