24#include "WrappedAudioOutputBase.h"
25#include "BackgroundAudioGain.h"
26#include "BackgroundAudioBuffers.h"
27#include "libespeak-ng/espeak-ng/speak_lib.h"
28#include "libespeak-ng/phoneme/phonindex.h"
29#include "libespeak-ng/phoneme/phontab.h"
30#include "libespeak-ng/phoneme/phondata.h"
31#include "libespeak-ng/phoneme/intonations.h"
34extern const unsigned char __espeakng_dict[];
35extern size_t __espeakng_dictlen;
55template<
class DataBuffer>
99 _gain = (int32_t)(scale * (1 << 16));
118 espeak_SetParameter(espeakRATE, rate, 0);
127 espeak_SetParameter(espeakPITCH, pitch, 0);
136 espeak_SetParameter(espeakWORDGAP, gap, 0);
145 if (_playing || !_voice || !_voiceLen || !_out) {
149#ifdef ARDUINO_ARCH_RP2040
150 _workIRQ = user_irq_claim_unused(
true);
152 irq_set_exclusive_handler(_workIRQ, _irqStub);
153 irq_set_priority(_workIRQ, 0xc0);
154 irq_set_enabled(_workIRQ,
true);
157 espeak_EnableSingleStep();
158 espeak_InstallDict(__espeakng_dict, __espeakng_dictlen);
159 espeak_InstallPhonIndex(_phonindex,
sizeof(_phonindex));
160 espeak_InstallPhonTab(_phontab,
sizeof(_phontab));
161 espeak_InstallPhonData(_phondata,
sizeof(_phondata));
162 espeak_InstallIntonations(_intonations,
sizeof(_intonations));
163 espeak_InstallVoice(_voice, _voiceLen);
165 int samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCH_PLAYBACK, 20,
nullptr, 0);
166 espeak_SetVoiceByFile(
"INTERNAL");
167 espeak_SetSynthCallback(_speechCB);
170 _out->setBuffers(5, framelen);
171 _out->onTransmit(&_cb, (
void *)
this);
172 _out->setBitsPerSample(16);
173 _out->setStereo(
true);
174 _out->setFrequency(samplerate);
178 uint16_t zeros[32] __attribute__((aligned(4))) = {};
179 while (_out->availableForWrite() > 32 * 2) {
180 _out->write((uint8_t *)zeros,
sizeof(zeros));
193#ifdef ARDUINO_ARCH_RP2040
194 irq_set_enabled(_workIRQ,
false);
195 user_irq_unclaim(_workIRQ);
229 size_t write(
const void *data,
size_t len) {
230 return _ib.write((
const uint8_t *)data, len);
243 return write((
const void *)
string, strlen(
string) + 1);
252 size_t speak(
const String &
string) {
253 return speak(
string.c_str());
269 return _ib.availableForWrite();
278 return _ib.available();
287 return !
available() && !_generatingSpeech;
369 _generatingSpeech =
false;
371 espeak_SynthesizeOneStep(&mono);
372 espeak_AbortSynthesis();
377#ifdef ARDUINO_ARCH_RP2040
378 static void _irqStub() {
382 static void _cb(
void *ptr) {
387 static void _cb(
void *ptr) {
392 static int _speechCB(
short *data,
int count, espeak_EVENT *events) {
396 void generateOneFrame() {
400 if (!_generatingSpeech) {
401 if (_ib.available()) {
402 const uint8_t *b = _ib.buffer();
403 for (
int i = 0; i < (int)_ib.available(); i++) {
405 espeak_Synth(_ib.buffer(), i, 0, (espeak_POSITION_TYPE)0, 0, espeakCHARS_AUTO, 0,
this);
406 _generatingSpeech =
true;
413 if (_generatingSpeech && !_frameLen) {
416 _frameLen = std::min(espeak_SynthesizeOneStep(&mono), framelen);
418 int16_t *ptr = _frame;
419 for (
int i = 0; i < _frameLen; i++) {
424 ApplyGain(_frame, _frameLen * 2, _gain);
426 if (!espeak_SynthesisGenerateNext()) {
427 _generatingSpeech =
false;
428 _ib.shiftUp(strlen((
const char *)_ib.buffer()) + 1);
434#ifdef ARDUINO_ARCH_RP2040
438 while (_out->availableForWrite() >= (
int)(framelen * 4)) {
439 if (!_frameLen && !_paused) {
442 if (_paused || !_frameLen) {
443 bzero(_frame,
sizeof(_frame));
444 assert(_out->write((uint8_t *)_frame,
sizeof(_frame)) ==
sizeof(_frame));
446 assert(_out->write((uint8_t *)_frame, _frameLen * 4) == (
size_t)(_frameLen * 4));
450#ifdef ARDUINO_ARCH_RP2040
455#ifdef ARDUINO_ARCH_RP2040
456 static uint8_t _workIRQ;
461 AudioOutputBase *_out;
462 bool _playing =
false;
463 bool _paused =
false;
465 int32_t _gain = 1 << 16;
466 bool _generatingSpeech =
false;
467 static constexpr int framelen = 1324;
468 int16_t _frame[framelen * 2];
471 const unsigned char *_dict;
473 const unsigned char *_voice;
477 uint32_t _frames = 0;
478 uint32_t _shifts = 0;
479 uint32_t _underflows = 0;
480 uint32_t _errors = 0;
484#ifdef ARDUINO_ARCH_RP2040
Interrupt-driven ESpeak-NG instance. Generates a full frame of samples each cycle and uses the RawBuf...
Definition BackgroundAudioSpeech.h:56
bool done()
Determine if no more speech is present in the buffer.
Definition BackgroundAudioSpeech.h:286
void setWordGap(int gap)
Adjust the interword gap after begin()
Definition BackgroundAudioSpeech.h:135
uint32_t underflows()
Get the number of times the speaker has underflowed waiting on raw data since begin
Definition BackgroundAudioSpeech.h:313
bool playing()
Determines if the speaker has been started.
Definition BackgroundAudioSpeech.h:207
size_t speak(const char *string)
Speaks a C-String.
Definition BackgroundAudioSpeech.h:239
BackgroundAudioSpeechClass(AudioOutputBase &d)
Construct an output device using the specified physical audio output.
Definition BackgroundAudioSpeech.h:70
bool setDevice(AudioOutputBase *d)
Set an output device before begin
Definition BackgroundAudioSpeech.h:85
bool paused()
Determine if the playback is paused.
Definition BackgroundAudioSpeech.h:347
uint32_t shifts()
Get the number of input data shifts processed by decoder since begin
Definition BackgroundAudioSpeech.h:304
void setPitch(int pitch)
Adjust the pitch, 0...99, with 50 default. After begin()
Definition BackgroundAudioSpeech.h:126
void pause()
Pause the decoder. Won't process raw input data and will transmit silence.
Definition BackgroundAudioSpeech.h:338
uint32_t frames()
Get number of "frames" processed by speaker.
Definition BackgroundAudioSpeech.h:295
uint32_t dumps()
Get the number of full buffer dumps (catastrophic data error) since begin
Definition BackgroundAudioSpeech.h:331
size_t availableForWrite()
Gets number of bytes available to write to raw buffer.
Definition BackgroundAudioSpeech.h:268
void unpause()
Unpause previously paused playback. Will start processing input data again.
Definition BackgroundAudioSpeech.h:355
bool begin()
Starts the background speaker. Will initialize the output device and start sending silence immediatel...
Definition BackgroundAudioSpeech.h:144
size_t available()
Gets number of bytes already in the raw buffer.
Definition BackgroundAudioSpeech.h:277
size_t speak(const String &string)
Speaks an Arduino String.
Definition BackgroundAudioSpeech.h:252
void setRate(int rate)
Set the speaking rate in ~wpm, after calling begin()
Definition BackgroundAudioSpeech.h:117
void end()
Stops the process and the calls the output device's end to shut it down, too.
Definition BackgroundAudioSpeech.h:191
size_t write(const void *data, size_t len)
Writes a block of raw data to the decoder's buffer.
Definition BackgroundAudioSpeech.h:229
void setVoice(BackgroundAudioVoice &v)
Sets the voice parameters (language customization)
Definition BackgroundAudioSpeech.h:107
void flush()
Flushes any existing raw data, resets the processor to start a new speaking.
Definition BackgroundAudioSpeech.h:366
void setGain(float scale)
Set the gain multiplier (volume) for the stream. Takes effect immediately.
Definition BackgroundAudioSpeech.h:98
uint32_t errors()
Get the number of decoder errors since begin
Definition BackgroundAudioSpeech.h:322
Structure to collect a ESpeak-NG voice with its human-readable name.
Definition BackgroundAudioSpeech.h:40
const char * name
Definition BackgroundAudioSpeech.h:42
const unsigned char * data
Definition BackgroundAudioSpeech.h:46
size_t len
Definition BackgroundAudioSpeech.h:44