Speech
#include "libtini/audio.h"
The SSI-263 on the slot-4 card speaks prepared phrases and numbers. tools/speech.py changes text into phonemes on the host. The game identifies phrases by generated names. The audio driver sends one phoneme in each update.
| Function | Purpose |
|---|---|
ti_speech_bind | Select the phrase bank |
ti_speech_say | Queue a phrase, or interrupt with a phrase |
ti_speech_number | Queue a number from 0 to 9999 |
ti_speech_busy | Tell if a phrase speaks or waits |
ti_speech_stop | Cancel all speech and power down |
ti_speech_voice | Set preset, pitch and rate |
Prepare speech
Speech is a part of the audio driver. Set speech in the audio configuration. Start audio. Then bind the bank that tools/speech.py made. Call ti_audio_update frequently. It sends the next phoneme when the chip reports that the last phoneme is complete.
python tools/speech.py speech.json --preview
python tools/speech.py speech.json --output build/my_speech.h --symbol my_speech
#include "my_speech.h" /* SAY_READY, SAY_GAME_OVER, ... and my_speech */
static ti_audio_config audio = {TI_AUDIO_MOCKINGBOARD, 1, 1, 0, 0};
ti_audio_init(&audio);
ti_speech_bind(&my_speech);
ti_speech_say(SAY_READY, 1);
ti_speech_number(score, 1); /* "one thousand nine hundred eighty four" */
Music, effects and speech and Data formats describe the phrase file and the vocabulary of the compiler.
Queue and priorities
One phrase speaks, and a maximum of four phrases wait (TI_SPEECH_QUEUE). A priority is 0-127. Of the phrases that wait, the phrase with the highest priority speaks next. Phrases with the same priority keep their order.
To start a phrase immediately, add TI_SPEECH_INTERRUPT (128) to its priority. The new phrase stops the current phrase when its priority is the same or higher. The queue of phrases that wait does not change. A number is one queue item, also when it has several words.
Constants and types
| Name | Value | Meaning |
|---|---|---|
TI_SPEECH_QUEUE | 4 | Items that can wait in addition to the item that speaks |
TI_SPEECH_INTERRUPT | 128 | Priority flag: replace the current phrase |
ti_phrase
typedef struct ti_phrase { const uint8_t *data; uint8_t length; } ti_phrase;
One prepared phrase: 1-255 SSI-263 phoneme bytes in near memory. Each phoneme is a separate write to the chip, also when the same phoneme repeats.
ti_speech_bank
typedef struct ti_speech_bank {
const ti_phrase *phrases;
uint8_t count;
const uint8_t *number_ids; /* 0..19, twenty..ninety, hundred, thousand; NULL omits numbers */
} ti_speech_bank;
A bank is a table of phrases. Optionally it also gives the phrase numbers of the thirty number words: zero to nineteen, twenty to ninety, hundred and thousand. tools/speech.py makes the full bank. With --no-numbers, it does not add the number words and sets number_ids to NULL. The driver uses the bank and all its data until the next bind or until audio stops.
Functions
ti_speech_bind
ti_error ti_speech_bind(const ti_speech_bank *bank);
This function checks the bank and makes it the current bank. It cancels the speech in progress. You can also bind a bank before ti_audio_init.
Returns
TI_OK; TI_E_ARGUMENT for a bank, phrase table or number table that the function cannot read, or zero phrases; TI_E_RANGE for an empty phrase, a phrase that the function cannot read, or a number word that is not a phrase of the bank.
ti_speech_say
ti_error ti_speech_say(uint8_t phrase, uint8_t priority);
This function queues phrase number phrase of the bound bank. With TI_SPEECH_INTERRUPT, it starts the phrase immediately. The function returns immediately. The speech continues in ti_audio_update.
Returns
TI_OK | The phrase is in the queue or speaks. |
TI_E_RANGE | No bank is bound, or the phrase number is not less than the count of the bank. |
TI_E_UNAVAILABLE | Audio does not run, speech is not enabled, or a speech timeout occurred. After a timeout, speech stays off until audio starts again. |
TI_E_BUSY | An interrupt phrase has a lower priority than the phrase that speaks. |
TI_E_FULL | Four items already wait. |
ti_speech_number
ti_error ti_speech_number(uint16_t value, uint8_t priority);
This function queues a number as usual cardinal English, without "and". For example, 1001 is "one thousand one" and 1984 is "one thousand nine hundred eighty four". It joins a maximum of six words into one queue item. This code is a separate archive module. The linker adds it only to programs that call it.
Returns
The same results as ti_speech_say, with these differences: TI_E_STATE when no bank is bound, TI_E_RANGE above 9999, and TI_E_UNAVAILABLE when the bank has no number words.
ti_speech_busy
uint8_t ti_speech_busy(void);
This function returns nonzero while a phrase speaks or waits. A game can use it to skip a minor phrase when a different phrase plays: if (!ti_speech_busy()) ti_speech_say(SAY_POWER, 1);
ti_speech_stop
void ti_speech_stop(void);
This function cancels the current phrase and the waiting phrases, and powers down the SSI-263.
ti_speech_voice
ti_error ti_speech_voice(uint8_t preset, uint8_t pitch, uint8_t rate);
This function cancels the waiting speech and sets the voice. preset 0-2 selects one of three articulation and amplitude settings. pitch is the SSI-263 inflection value. rate 0-15 goes into the rate field of the chip. Audio init sets preset 0, pitch 0x40 and rate 10. The chip stays powered down until the next phrase.
Returns
TI_OK; TI_E_UNAVAILABLE when audio does not run or speech is not enabled; TI_E_ARGUMENT for a preset above 2 or a rate above 15.
How the driver controls the SSI-263
- On a native Phasor, the interrupt handler records the completion signal of the chip. It acknowledges the signal with a new write of the inflection register. This write does not change the phoneme.
- On a Mockingboard, the driver polls the CA1 flag of the VIA. The CA1 interrupt stays disabled.
- On a Mockingboard, SSI writes share the port of the first VIA with the first AY chip. Thus after each SSI write, the driver restores the port configuration and sends the registers of that chip again. AY writes use the port register without handshake. Thus they do not clear CA1.
- When a phoneme does not report completion in two seconds of device ticks, the driver powers down speech and cancels the queue.
ti_audio_updatethen returnsTI_E_TIMINGone time. Speech calls returnTI_E_UNAVAILABLEuntil audio stops and starts again. Music and effects continue.
In standalone ONE//e mode, speech needs Appletini firmware F1.3.2 or later. F1.3.2 clocks the two speech engines from the virtual PHI0 in standalone mode. When a speech chip is configured, the driver tries to use it; the configuration does not prove that a chip is present. Show essential messages on the screen as captions too.