kopia lustrzana https://github.com/OpenRTX/OpenRTX
Refactored voicePrompts.h, aligned function names of voice prompt API to OpenRTX coding style
rodzic
5840f459fa
commit
df5341e103
|
@ -16,25 +16,20 @@
|
|||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
#ifndef voice_prompts_h_included
|
||||
#define voice_prompts_h_included
|
||||
#ifndef VOICEPROMPTS_H
|
||||
#define VOICEPROMPTS_H
|
||||
|
||||
#include <datatypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Voice prompts are encoded using the codec2 file format used by ffmpeg
|
||||
#define CODEC2_HEADER_SIZE 7
|
||||
|
||||
/*
|
||||
Please note, these prompts represent spoken words or phrases which are not in
|
||||
the UI string table, for example letters of the alphabet, digits, and
|
||||
descriptive words not displayed in the UI.
|
||||
The voice prompt data file stores these first, then after the data for these
|
||||
prompts, the data for the indexed string table phrases.
|
||||
*/
|
||||
/* Please note! this enum must match the order of prompts defined in the
|
||||
wordlist.csv file in the voicePrompts generator project.
|
||||
*/
|
||||
/**
|
||||
* List of voice prompts for spoken words or phrases which are not in the UI
|
||||
* string table. The voice prompt data file stores these first, then after the
|
||||
* data for these prompts, the data for the indexed string table phrases.
|
||||
*
|
||||
* WARNING: this enum must match the order of prompts defined in the
|
||||
* wordlist.csv file in the voicePrompts generator project.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
PROMPT_SILENCE, //
|
||||
|
@ -181,19 +176,12 @@ typedef enum
|
|||
PROMPT_CUSTOM9, // parrot
|
||||
PROMPT_CUSTOM10, // unused
|
||||
NUM_VOICE_PROMPTS,
|
||||
} voicePrompt_t;
|
||||
}
|
||||
voicePrompt_t;
|
||||
|
||||
// PROMPT_VOICE_NAME is always the very last prompt after the indexed prompts
|
||||
// from the strings table.
|
||||
#define PROMPT_VOICE_NAME \
|
||||
(NUM_VOICE_PROMPTS + (sizeof(stringsTable_t) / sizeof(char*)))
|
||||
/*
|
||||
These flags govern how vpQueueString operates.
|
||||
For example, when editing, it is desireable to hear spaces, capitals and
|
||||
extended symbols.
|
||||
When just arrowing through menus, spaces, extended symbols etc should not be
|
||||
announced.
|
||||
*/
|
||||
/**
|
||||
* Flags controlling how vp_queueString operates.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
vpAnnounceCaps = 0x01,
|
||||
|
@ -203,30 +191,27 @@ typedef enum
|
|||
vpAnnounceLessCommonSymbols = 0x10,
|
||||
vpAnnounceASCIIValueForUnknownChars = 0x20,
|
||||
vpAnnouncePhoneticRendering = 0x40,
|
||||
} VoicePromptFlags_T;
|
||||
/*
|
||||
These queuing flags determine if speech is interrupted, played
|
||||
immediately, whether prompts are queued for values, etc.
|
||||
They are necessary because for example if you call the announceXX functions
|
||||
consecutively, it is only desireable to initially stop speech in
|
||||
progress and only play after the last prompt is queued.
|
||||
If however calling an announceXX function in isolation, normally any prompt in
|
||||
progress should be interrupted and play should be called immediately.
|
||||
At Voice level 1, changing channels in memory mode or frequencies in VFO mode
|
||||
is indicated by a beep however if F1 is pressed, we will still say the current
|
||||
channel name or frequency. This is accomplished by queueing but not playing a
|
||||
prompt.
|
||||
*/
|
||||
}
|
||||
VoicePromptFlags_T;
|
||||
|
||||
/**
|
||||
* Queuing flags determining if speech is interrupted, played immediately,
|
||||
* whether prompts are queued for values, etc.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
vpqDefault = 0,
|
||||
vpqInit = 0x01, // stop any voice prompts already in progress.
|
||||
vpqPlayImmediately = 0x02, // call play after queue at all levels.
|
||||
vpqDefault = 0,
|
||||
vpqInit = 0x01, // stop any voice prompts already in progress.
|
||||
vpqPlayImmediately = 0x02, // call play after queue at all levels.
|
||||
vpqPlayImmediatelyAtMediumOrHigher = 0x04,
|
||||
vpqIncludeDescriptions = 0x08,
|
||||
vpqAddSeparatingSilence = 0x10
|
||||
} VoicePromptQueueFlags_T;
|
||||
}
|
||||
VoicePromptQueueFlags_T;
|
||||
|
||||
/**
|
||||
* Voice prompt verbosity levels.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
vpNone = 0,
|
||||
|
@ -234,43 +219,74 @@ typedef enum
|
|||
vpLow,
|
||||
vpMedium,
|
||||
vpHigh
|
||||
} VoicePromptVerbosity_T;
|
||||
}
|
||||
VoicePromptVerbosity_T;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* userWord;
|
||||
const voicePrompt_t vp;
|
||||
} userDictEntry;
|
||||
/**
|
||||
* Initialise the voice prompt system and load vp table of contents.
|
||||
*/
|
||||
void vp_init();
|
||||
|
||||
extern bool vpDataIsLoaded;
|
||||
extern const uint32_t VOICE_PROMPTS_FLASH_HEADER_ADDRESS;
|
||||
extern VoicePromptVerbosity_T vpLevel;
|
||||
// Loads just the TOC from Flash and stores in RAM for fast access.
|
||||
void vpCacheInit(void);
|
||||
// Call before building the prompt sequence to clear prompt in progress.
|
||||
void vpInit(void);
|
||||
// This function appends an individual prompt item to the prompt queue.
|
||||
// This can be a single letter, number, or a phrase.
|
||||
void vpQueuePrompt(uint16_t prompt);
|
||||
// This function appends the spelling of a complete string to the queue.
|
||||
// It is used to pronounce strings for which we do not have a recorded voice
|
||||
// prompt.
|
||||
void vpQueueString(char* promptString, VoicePromptFlags_T flags);
|
||||
// This function appends a signed integer to the queue.
|
||||
void vpQueueInteger(int32_t value);
|
||||
// This function appends a text string from the current language to the queue.
|
||||
// e.g. currentLanguage->off
|
||||
// These are recorded prompts which correspond to the strings in the strings
|
||||
// table.
|
||||
void vpQueueStringTableEntry(const char* const*);
|
||||
/**
|
||||
* Terminate the currently ongoing prompt and shutdown the voice prompt system.
|
||||
*/
|
||||
void vp_terminate();
|
||||
|
||||
void vpPlay(void); // Starts prompt playback
|
||||
void vpTick(); // called to process vp data being decoded.
|
||||
extern bool vpIsPlaying(void);
|
||||
bool vpHasDataToPlay(void);
|
||||
void vpTerminate(void);
|
||||
bool vpCheckHeader(uint32_t* bufferAddress);
|
||||
int vp_open(char *vp_name);
|
||||
void vp_close();
|
||||
/**
|
||||
* Clear the currently in-progress prompt, to be called before building a new
|
||||
* voice prompt sequence.
|
||||
*/
|
||||
void vp_clearCurrPrompt();
|
||||
|
||||
/**
|
||||
* Append an individual prompt item to the prompt queue.
|
||||
*
|
||||
* @param prompt: voice prompt ID.
|
||||
*/
|
||||
void vp_queuePrompt(const uint16_t prompt);
|
||||
|
||||
/**
|
||||
* Append the spelling of a complete string to the queue.
|
||||
*
|
||||
* @param promptString: string to be spelled.
|
||||
* @param flags: control flags.
|
||||
*/
|
||||
void vp_queueString(char* promptString, VoicePromptFlags_T flags);
|
||||
|
||||
/**
|
||||
* Append a signed integer to the queue.
|
||||
*
|
||||
* @param value: value to be appended.
|
||||
*/
|
||||
void vp_queueInteger(const int32_t value);
|
||||
|
||||
/**
|
||||
* Append a text string from the current language to the queue.
|
||||
*/
|
||||
void vp_queueStringTableEntry(const char* const* stringTableStringPtr);
|
||||
|
||||
/**
|
||||
* Start prompt playback.
|
||||
*/
|
||||
void vp_play();
|
||||
|
||||
/**
|
||||
* Function handling vp data decoding, to be called periodically.
|
||||
*/
|
||||
void vp_tick();
|
||||
|
||||
/**
|
||||
* Check if a voice prompt is being played.
|
||||
*
|
||||
* @return true if a voice prompt is being played.
|
||||
*/
|
||||
bool vp_isPlaying();
|
||||
|
||||
/**
|
||||
* Check if the voice prompt sequence is empty.
|
||||
*
|
||||
* @return true if the voice prompt sequence is empty.
|
||||
*/
|
||||
bool vp_sequenceNotEmpty();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,7 +44,7 @@ void openrtx_init()
|
|||
gfx_init(); // Initialize display and graphics driver
|
||||
kbd_init(); // Initialize keyboard driver
|
||||
ui_init(); // Initialize user interface
|
||||
vpCacheInit(); // Checks to see if voice prompts are loaded and initializes them
|
||||
vp_init(); // Initialize voice prompts
|
||||
#ifdef SCREEN_CONTRAST
|
||||
display_setContrast(state.settings.contrast);
|
||||
#endif
|
||||
|
|
|
@ -75,7 +75,7 @@ void *ui_threadFunc(void *arg)
|
|||
ui_saveState(); // Save local state copy
|
||||
pthread_mutex_unlock(&state_mutex); // Unlock r/w access to radio state
|
||||
|
||||
vpTick(); // continue playing voice prompts in progress if any.
|
||||
vp_tick(); // continue playing voice prompts in progress if any.
|
||||
|
||||
// If synchronization needed take mutex and update RTX configuration
|
||||
if(sync_rtx)
|
||||
|
|
|
@ -31,26 +31,26 @@
|
|||
|
||||
#include "interfaces/cps_io.h"
|
||||
|
||||
static void vpInitIfNeeded(VoicePromptQueueFlags_T flags)
|
||||
static void vp_clearCurrPromptIfNeeded(VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
if (flags & vpqInit) vpInit();
|
||||
if (flags & vpqInit) vp_clearCurrPrompt();
|
||||
}
|
||||
|
||||
static void vpPlayIfNeeded(VoicePromptQueueFlags_T flags)
|
||||
static void vp_playIfNeeded(VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
uint8_t vpLevel = state.settings.vpLevel;
|
||||
|
||||
if ((flags & vpqPlayImmediately) ||
|
||||
((flags & vpqPlayImmediatelyAtMediumOrHigher) && (vpLevel >= vpMedium)))
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
static void addSilenceIfNeeded(VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
if ((flags & vpqAddSeparatingSilence) == 0) return;
|
||||
|
||||
vpQueuePrompt(PROMPT_SILENCE);
|
||||
vpQueuePrompt(PROMPT_SILENCE);
|
||||
vp_queuePrompt(PROMPT_SILENCE);
|
||||
vp_queuePrompt(PROMPT_SILENCE);
|
||||
}
|
||||
|
||||
static void removeUnnecessaryZerosFromVoicePrompts(char* str)
|
||||
|
@ -69,32 +69,32 @@ static void removeUnnecessaryZerosFromVoicePrompts(char* str)
|
|||
|
||||
void announceVFO()
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
vpQueuePrompt(PROMPT_VFO);
|
||||
vp_queuePrompt(PROMPT_VFO);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void announceChannelName(channel_t* channel, uint16_t channelIndex,
|
||||
VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions)
|
||||
{
|
||||
vpQueuePrompt(PROMPT_CHANNEL);
|
||||
vp_queuePrompt(PROMPT_CHANNEL);
|
||||
}
|
||||
vpQueueInteger(channelIndex);
|
||||
vp_queueInteger(channelIndex);
|
||||
|
||||
// Only queue the name if it is not the same as the raw number.
|
||||
// Otherwise the radio will say channel 1 1 for channel 1.
|
||||
char numAsStr[16] = "\0";
|
||||
snprintf(numAsStr, 16, "%d", channelIndex);
|
||||
if (strcmp(numAsStr, channel->name) != 0)
|
||||
vpQueueString(channel->name, vpAnnounceCommonSymbols);
|
||||
vp_queueString(channel->name, vpAnnounceCommonSymbols);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void vpQueueFrequency(freq_t freq)
|
||||
|
@ -106,77 +106,77 @@ void vpQueueFrequency(freq_t freq)
|
|||
snprintf(buffer, 16, "%d.%05d", mhz, khz);
|
||||
removeUnnecessaryZerosFromVoicePrompts(buffer);
|
||||
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
|
||||
vpQueuePrompt(PROMPT_MEGAHERTZ);
|
||||
vp_queuePrompt(PROMPT_MEGAHERTZ);
|
||||
}
|
||||
|
||||
void announceFrequencies(freq_t rx, freq_t tx, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
// If rx and tx frequencies differ, announce both, otherwise just one
|
||||
if (rx == tx)
|
||||
vpQueueFrequency(rx);
|
||||
else
|
||||
{
|
||||
vpQueuePrompt(PROMPT_RECEIVE);
|
||||
vp_queuePrompt(PROMPT_RECEIVE);
|
||||
vpQueueFrequency(rx);
|
||||
vpQueuePrompt(PROMPT_TRANSMIT);
|
||||
vp_queuePrompt(PROMPT_TRANSMIT);
|
||||
vpQueueFrequency(tx);
|
||||
}
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceRadioMode(uint8_t mode, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_MODE);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_MODE);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case OPMODE_DMR:
|
||||
vpQueueStringTableEntry(¤tLanguage->dmr);
|
||||
vp_queueStringTableEntry(¤tLanguage->dmr);
|
||||
break;
|
||||
case OPMODE_FM:
|
||||
vpQueueStringTableEntry(¤tLanguage->fm);
|
||||
vp_queueStringTableEntry(¤tLanguage->fm);
|
||||
break;
|
||||
case OPMODE_M17:
|
||||
vpQueueStringTableEntry(¤tLanguage->m17);
|
||||
vp_queueStringTableEntry(¤tLanguage->m17);
|
||||
break;
|
||||
}
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceBandwidth(uint8_t bandwidth, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
if (bandwidth > BW_25) bandwidth = BW_25; // Should probably never happen!
|
||||
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_BANDWIDTH);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_BANDWIDTH);
|
||||
|
||||
char* bandwidths[] = {"12.5", "20", "25"};
|
||||
vpQueueString(bandwidths[bandwidth], vpAnnounceCommonSymbols);
|
||||
vpQueuePrompt(PROMPT_KILOHERTZ);
|
||||
vp_queueString(bandwidths[bandwidth], vpAnnounceCommonSymbols);
|
||||
vp_queuePrompt(PROMPT_KILOHERTZ);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void anouncePower(float power, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
char buffer[16] = "\0";
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_POWER);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_POWER);
|
||||
|
||||
snprintf(buffer, 16, "%1.1f", power);
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vpQueuePrompt(PROMPT_WATTS);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queuePrompt(PROMPT_WATTS);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceChannelSummary(channel_t* channel, uint16_t channelIndex,
|
||||
|
@ -184,7 +184,7 @@ void announceChannelSummary(channel_t* channel, uint16_t channelIndex,
|
|||
{
|
||||
if (!channel) return;
|
||||
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
VoicePromptQueueFlags_T localFlags = vpqAddSeparatingSilence;
|
||||
// Force on the descriptions for level 3.
|
||||
|
@ -192,7 +192,7 @@ void announceChannelSummary(channel_t* channel, uint16_t channelIndex,
|
|||
// If VFO mode, announce VFO.
|
||||
// channelIndex will be 0 if called from VFO mode.
|
||||
if (channelIndex == 0)
|
||||
vpQueuePrompt(PROMPT_VFO);
|
||||
vp_queuePrompt(PROMPT_VFO);
|
||||
else
|
||||
announceChannelName(channel, channelIndex, localFlags);
|
||||
announceFrequencies(channel->rx_frequency, channel->tx_frequency,
|
||||
|
@ -233,7 +233,7 @@ void announceChannelSummary(channel_t* channel, uint16_t channelIndex,
|
|||
if (channelIndex > 0) // i.e. not called from VFO.
|
||||
announceBank(bank, localFlags);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void AnnounceInputChar(char ch)
|
||||
|
@ -241,72 +241,72 @@ void AnnounceInputChar(char ch)
|
|||
char buf[2] = "\0";
|
||||
buf[0] = ch;
|
||||
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
uint8_t flags = vpAnnounceCaps | vpAnnounceSpace | vpAnnounceCommonSymbols |
|
||||
vpAnnounceLessCommonSymbols;
|
||||
|
||||
vpQueueString(buf, flags);
|
||||
vp_queueString(buf, flags);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void announceInputReceiveOrTransmit(bool tx, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (tx)
|
||||
vpQueuePrompt(PROMPT_TRANSMIT);
|
||||
vp_queuePrompt(PROMPT_TRANSMIT);
|
||||
else
|
||||
vpQueuePrompt(PROMPT_RECEIVE);
|
||||
vp_queuePrompt(PROMPT_RECEIVE);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void ReplayLastPrompt()
|
||||
{
|
||||
if (vpIsPlaying())
|
||||
vpTerminate();
|
||||
if (vp_isPlaying())
|
||||
vp_terminate();
|
||||
else
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void announceError(VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->error);
|
||||
vp_queueStringTableEntry(¤tLanguage->error);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceText(char* text, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
if (!text || !*text) return;
|
||||
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
// See if we have a prompt for this string.
|
||||
int offset = GetEnglishStringTableOffset(text);
|
||||
|
||||
if (offset != -1)
|
||||
vpQueueStringTableEntry(
|
||||
vp_queueStringTableEntry(
|
||||
(const char* const*)(¤tLanguage->languageName + offset));
|
||||
else // Just spell it out
|
||||
vpQueueString(text, vpAnnounceCommonSymbols);
|
||||
vp_queueString(text, vpAnnounceCommonSymbols);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceCTCSS(bool rxToneEnabled, uint8_t rxTone, bool txToneEnabled,
|
||||
uint8_t txTone, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (!rxToneEnabled && !txToneEnabled)
|
||||
{
|
||||
vpQueuePrompt(PROMPT_TONE);
|
||||
vpQueueStringTableEntry(¤tLanguage->off);
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_queuePrompt(PROMPT_TONE);
|
||||
vp_queueStringTableEntry(¤tLanguage->off);
|
||||
vp_playIfNeeded(flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -315,68 +315,68 @@ void announceCTCSS(bool rxToneEnabled, uint8_t rxTone, bool txToneEnabled,
|
|||
// If the rx and tx tones are the same and both are enabled, just say Tone.
|
||||
if ((rxToneEnabled && txToneEnabled) && (rxTone == txTone))
|
||||
{
|
||||
vpQueuePrompt(PROMPT_TONE);
|
||||
vp_queuePrompt(PROMPT_TONE);
|
||||
snprintf(buffer, 16, "%3.1f", ctcss_tone[rxTone] / 10.0f);
|
||||
vpQueueString(buffer, vpqDefault);
|
||||
vpQueuePrompt(PROMPT_HERTZ);
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_queueString(buffer, vpqDefault);
|
||||
vp_queuePrompt(PROMPT_HERTZ);
|
||||
vp_playIfNeeded(flags);
|
||||
return;
|
||||
}
|
||||
// Speak the individual rx and tx tones.
|
||||
if (rxToneEnabled)
|
||||
{
|
||||
vpQueuePrompt(PROMPT_RECEIVE);
|
||||
vpQueuePrompt(PROMPT_TONE);
|
||||
vp_queuePrompt(PROMPT_RECEIVE);
|
||||
vp_queuePrompt(PROMPT_TONE);
|
||||
snprintf(buffer, 16, "%3.1f", ctcss_tone[rxTone] / 10.0f);
|
||||
vpQueueString(buffer, vpqDefault);
|
||||
vpQueuePrompt(PROMPT_HERTZ);
|
||||
vp_queueString(buffer, vpqDefault);
|
||||
vp_queuePrompt(PROMPT_HERTZ);
|
||||
}
|
||||
if (txToneEnabled)
|
||||
{
|
||||
vpQueuePrompt(PROMPT_TRANSMIT);
|
||||
vpQueuePrompt(PROMPT_TONE);
|
||||
vp_queuePrompt(PROMPT_TRANSMIT);
|
||||
vp_queuePrompt(PROMPT_TONE);
|
||||
snprintf(buffer, 16, "%3.1f", ctcss_tone[txTone] / 10.0f);
|
||||
vpQueueString(buffer, vpqDefault);
|
||||
vpQueuePrompt(PROMPT_HERTZ);
|
||||
vp_queueString(buffer, vpqDefault);
|
||||
vp_queuePrompt(PROMPT_HERTZ);
|
||||
}
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceBrightness(uint8_t brightness, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions)
|
||||
vpQueueStringTableEntry(¤tLanguage->brightness);
|
||||
vp_queueStringTableEntry(¤tLanguage->brightness);
|
||||
|
||||
vpQueueInteger(brightness);
|
||||
vp_queueInteger(brightness);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceSquelch(uint8_t squelch, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_SQUELCH);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_SQUELCH);
|
||||
|
||||
vpQueueInteger(squelch);
|
||||
vp_queueInteger(squelch);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceContact(contact_t* contact, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
if (!contact) return;
|
||||
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_CONTACT);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_CONTACT);
|
||||
|
||||
if (contact->name[0]) vpQueueString(contact->name, vpAnnounceCommonSymbols);
|
||||
if (contact->name[0]) vp_queueString(contact->name, vpAnnounceCommonSymbols);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceContactWithIndex(uint16_t index, VoicePromptQueueFlags_T flags)
|
||||
|
@ -392,69 +392,69 @@ void announceContactWithIndex(uint16_t index, VoicePromptQueueFlags_T flags)
|
|||
|
||||
void announceTimeslot(uint8_t timeslot, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_TIMESLOT);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_TIMESLOT);
|
||||
|
||||
vpQueueInteger(timeslot);
|
||||
vp_queueInteger(timeslot);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceColorCode(uint8_t rxColorCode, uint8_t txColorCode,
|
||||
VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_COLORCODE);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_COLORCODE);
|
||||
|
||||
if (rxColorCode == txColorCode)
|
||||
{
|
||||
vpQueueInteger(rxColorCode);
|
||||
vp_queueInteger(rxColorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
vpQueuePrompt(PROMPT_RECEIVE);
|
||||
vpQueueInteger(rxColorCode);
|
||||
vpQueuePrompt(PROMPT_TRANSMIT);
|
||||
vpQueueInteger(txColorCode);
|
||||
vp_queuePrompt(PROMPT_RECEIVE);
|
||||
vp_queueInteger(rxColorCode);
|
||||
vp_queuePrompt(PROMPT_TRANSMIT);
|
||||
vp_queueInteger(txColorCode);
|
||||
}
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceBank(uint16_t bank, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
if (flags & vpqIncludeDescriptions)
|
||||
vpQueueStringTableEntry(¤tLanguage->banks);
|
||||
vp_queueStringTableEntry(¤tLanguage->banks);
|
||||
|
||||
if (state.bank_enabled)
|
||||
{
|
||||
bankHdr_t bank_hdr = {0};
|
||||
cps_readBankHeader(&bank_hdr, bank);
|
||||
vpQueueString(bank_hdr.name, vpAnnounceCommonSymbols);
|
||||
vp_queueString(bank_hdr.name, vpAnnounceCommonSymbols);
|
||||
}
|
||||
else
|
||||
vpQueueStringTableEntry(¤tLanguage->allChannels);
|
||||
vp_queueStringTableEntry(¤tLanguage->allChannels);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
void announceM17Info(channel_t* channel, VoicePromptQueueFlags_T flags)
|
||||
{
|
||||
if (!channel) return;
|
||||
|
||||
vpInitIfNeeded(flags);
|
||||
vp_clearCurrPromptIfNeeded(flags);
|
||||
if (state.m17_data.dst_addr[0])
|
||||
{
|
||||
if (flags & vpqIncludeDescriptions) vpQueuePrompt(PROMPT_DEST_ID);
|
||||
vpQueueString(state.m17_data.dst_addr, vpAnnounceCommonSymbols);
|
||||
if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_DEST_ID);
|
||||
vp_queueString(state.m17_data.dst_addr, vpAnnounceCommonSymbols);
|
||||
}
|
||||
else if (channel->m17.contact_index)
|
||||
announceContactWithIndex(channel->m17.contact_index, flags);
|
||||
|
||||
vpPlayIfNeeded(flags);
|
||||
vp_playIfNeeded(flags);
|
||||
}
|
||||
|
||||
#ifdef GPS_PRESENT
|
||||
|
@ -462,33 +462,33 @@ void announceGPSInfo()
|
|||
{
|
||||
if (!state.settings.gps_enabled) return;
|
||||
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
VoicePromptQueueFlags_T flags =
|
||||
vpqIncludeDescriptions | vpqAddSeparatingSilence;
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->gps);
|
||||
vp_queueStringTableEntry(¤tLanguage->gps);
|
||||
|
||||
switch (state.gps_data.fix_quality)
|
||||
{
|
||||
case 0:
|
||||
vpQueueStringTableEntry(¤tLanguage->noFix);
|
||||
vp_queueStringTableEntry(¤tLanguage->noFix);
|
||||
break;
|
||||
case 1:
|
||||
vpQueueString("SPS", vpAnnounceCommonSymbols);
|
||||
vp_queueString("SPS", vpAnnounceCommonSymbols);
|
||||
break;
|
||||
case 2:
|
||||
vpQueueString("DGPS", vpAnnounceCommonSymbols);
|
||||
vp_queueString("DGPS", vpAnnounceCommonSymbols);
|
||||
break;
|
||||
case 3:
|
||||
vpQueueString("PPS", vpAnnounceCommonSymbols);
|
||||
vp_queueString("PPS", vpAnnounceCommonSymbols);
|
||||
break;
|
||||
case 6:
|
||||
vpQueueStringTableEntry(¤tLanguage->fixLost);
|
||||
vp_queueStringTableEntry(¤tLanguage->fixLost);
|
||||
break;
|
||||
default:
|
||||
vpQueueStringTableEntry(¤tLanguage->error);
|
||||
vp_queueStringTableEntry(¤tLanguage->error);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -497,113 +497,113 @@ void announceGPSInfo()
|
|||
switch (state.gps_data.fix_type)
|
||||
{
|
||||
case 2:
|
||||
vpQueueString("2D", vpAnnounceCommonSymbols);
|
||||
vp_queueString("2D", vpAnnounceCommonSymbols);
|
||||
break;
|
||||
case 3:
|
||||
vpQueueString("3D", vpAnnounceCommonSymbols);
|
||||
vp_queueString("3D", vpAnnounceCommonSymbols);
|
||||
break;
|
||||
}
|
||||
addSilenceIfNeeded(flags);
|
||||
// lat/long
|
||||
char buffer[16] = "\0";
|
||||
vpQueuePrompt(PROMPT_LATITUDE);
|
||||
vp_queuePrompt(PROMPT_LATITUDE);
|
||||
snprintf(buffer, 16, "%8.6f", state.gps_data.latitude);
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vpQueuePrompt(PROMPT_NORTH);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queuePrompt(PROMPT_NORTH);
|
||||
float longitude = state.gps_data.longitude;
|
||||
voicePrompt_t direction = (longitude < 0) ? PROMPT_WEST : PROMPT_EAST;
|
||||
longitude = (longitude < 0) ? -longitude : longitude;
|
||||
snprintf(buffer, 16, "%8.6f", longitude);
|
||||
vpQueuePrompt(PROMPT_LONGITUDE);
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vpQueuePrompt(direction);
|
||||
vp_queuePrompt(PROMPT_LONGITUDE);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queuePrompt(direction);
|
||||
addSilenceIfNeeded(flags);
|
||||
// speed/altitude:
|
||||
vpQueuePrompt(PROMPT_SPEED);
|
||||
vp_queuePrompt(PROMPT_SPEED);
|
||||
snprintf(buffer, 16, "%4.1fkm/h", state.gps_data.speed);
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vpQueuePrompt(PROMPT_ALTITUDE);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queuePrompt(PROMPT_ALTITUDE);
|
||||
snprintf(buffer, 16, "%4.1fm", state.gps_data.altitude);
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
addSilenceIfNeeded(flags);
|
||||
|
||||
vpQueuePrompt(PROMPT_COMPASS);
|
||||
vp_queuePrompt(PROMPT_COMPASS);
|
||||
snprintf(buffer, 16, "%3.1f", state.gps_data.tmg_true);
|
||||
vpQueueString(buffer, vpAnnounceCommonSymbols);
|
||||
vpQueuePrompt(PROMPT_DEGREES);
|
||||
vp_queueString(buffer, vpAnnounceCommonSymbols);
|
||||
vp_queuePrompt(PROMPT_DEGREES);
|
||||
addSilenceIfNeeded(flags);
|
||||
|
||||
vpQueuePrompt(PROMPT_SATELLITES);
|
||||
vpQueueInteger(__builtin_popcount(state.gps_data.active_sats));
|
||||
vp_queuePrompt(PROMPT_SATELLITES);
|
||||
vp_queueInteger(__builtin_popcount(state.gps_data.active_sats));
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
#endif // GPS_PRESENT
|
||||
|
||||
void announceAboutScreen()
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->openRTX);
|
||||
vp_queueStringTableEntry(¤tLanguage->openRTX);
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->Niccolo);
|
||||
vpQueueStringTableEntry(¤tLanguage->Silvano);
|
||||
vpQueueStringTableEntry(¤tLanguage->Federico);
|
||||
vpQueueStringTableEntry(¤tLanguage->Fred);
|
||||
vpQueueStringTableEntry(¤tLanguage->Joseph);
|
||||
vp_queueStringTableEntry(¤tLanguage->Niccolo);
|
||||
vp_queueStringTableEntry(¤tLanguage->Silvano);
|
||||
vp_queueStringTableEntry(¤tLanguage->Federico);
|
||||
vp_queueStringTableEntry(¤tLanguage->Fred);
|
||||
vp_queueStringTableEntry(¤tLanguage->Joseph);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void announceBackupScreen()
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->flashBackup);
|
||||
vp_queueStringTableEntry(¤tLanguage->flashBackup);
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->connectToRTXTool);
|
||||
vpQueueStringTableEntry(¤tLanguage->toBackupFlashAnd);
|
||||
vpQueueStringTableEntry(¤tLanguage->pressPTTToStart);
|
||||
vpQueuePrompt(PROMPT_VP_UNAVAILABLE);
|
||||
vp_queueStringTableEntry(¤tLanguage->connectToRTXTool);
|
||||
vp_queueStringTableEntry(¤tLanguage->toBackupFlashAnd);
|
||||
vp_queueStringTableEntry(¤tLanguage->pressPTTToStart);
|
||||
vp_queuePrompt(PROMPT_VP_UNAVAILABLE);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void announceRestoreScreen()
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->flashRestore);
|
||||
vp_queueStringTableEntry(¤tLanguage->flashRestore);
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->connectToRTXTool);
|
||||
vpQueueStringTableEntry(¤tLanguage->toRestoreFlashAnd);
|
||||
vpQueueStringTableEntry(¤tLanguage->pressPTTToStart);
|
||||
vpQueuePrompt(PROMPT_VP_UNAVAILABLE);
|
||||
vp_queueStringTableEntry(¤tLanguage->connectToRTXTool);
|
||||
vp_queueStringTableEntry(¤tLanguage->toRestoreFlashAnd);
|
||||
vp_queueStringTableEntry(¤tLanguage->pressPTTToStart);
|
||||
vp_queuePrompt(PROMPT_VP_UNAVAILABLE);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
#ifdef RTC_PRESENT
|
||||
void announceSettingsTimeDate()
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
|
||||
vpQueueStringTableEntry(¤tLanguage->timeAndDate);
|
||||
vp_queueStringTableEntry(¤tLanguage->timeAndDate);
|
||||
|
||||
datetime_t local_time = utcToLocalTime(state.time, state.settings.utc_timezone);
|
||||
|
||||
char buffer[16] = "\0";
|
||||
snprintf(buffer, 16, "%02d/%02d/%02d", local_time.date, local_time.month,
|
||||
local_time.year);
|
||||
vpQueueString(buffer,
|
||||
vp_queueString(buffer,
|
||||
(vpAnnounceCommonSymbols | vpAnnounceLessCommonSymbols));
|
||||
|
||||
snprintf(buffer, 16, "%02d:%02d:%02d", local_time.hour, local_time.minute,
|
||||
local_time.second);
|
||||
vpQueueString(buffer,
|
||||
vp_queueString(buffer,
|
||||
(vpAnnounceCommonSymbols | vpAnnounceLessCommonSymbols));
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
#endif // RTC_PRESENT
|
||||
|
||||
|
@ -647,7 +647,7 @@ VoicePromptQueueFlags_T GetQueueFlagsForVoiceLevel()
|
|||
// Play immediately with descriptions unless speech is in progress.
|
||||
case vpHigh:
|
||||
flags |= vpqPlayImmediately;
|
||||
if (!vpIsPlaying()) flags |= vpqIncludeDescriptions;
|
||||
if (!vp_isPlaying()) flags |= vpqIncludeDescriptions;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,16 @@ const uint32_t VOICE_PROMPTS_DATA_VERSION = 0x1000; // v1000 OpenRTX
|
|||
// The length is the length in bytes of the data.
|
||||
static void GetCodec2Data(int offset, int length);
|
||||
|
||||
#define CODEC2_HEADER_SIZE 7
|
||||
|
||||
static FILE *voice_prompt_file = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* userWord;
|
||||
const voicePrompt_t vp;
|
||||
} userDictEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic;
|
||||
|
@ -50,7 +58,7 @@ typedef struct
|
|||
// offset into voice prompt vpc file where actual codec2 data starts.
|
||||
static uint32_t vpDataOffset = 0;
|
||||
// Each codec2 frame is 8 bytes.
|
||||
// 256 x 8 bytes
|
||||
// 256 x 8 bytes
|
||||
#define Codec2DataBufferSize 2048
|
||||
|
||||
bool vpDataIsLoaded = false;
|
||||
|
@ -70,7 +78,7 @@ typedef struct
|
|||
uint16_t buffer[VOICE_PROMPTS_SEQUENCE_BUFFER_SIZE];
|
||||
int pos; // index into above buffer.
|
||||
int length; // number of entries in above buffer.
|
||||
int codec2DataIndex; // index into current codec2 data
|
||||
int codec2DataIndex; // index into current codec2 data
|
||||
//(buffer content sent in lots of 8 byte frames.)
|
||||
int codec2DataLength; // length of codec2 data for current prompt.
|
||||
} vpSequence_t;
|
||||
|
@ -106,17 +114,25 @@ void vp_close()
|
|||
fclose(voice_prompt_file);
|
||||
}
|
||||
|
||||
void vpCacheInit(void)
|
||||
bool vpCheckHeader(uint32_t* bufferAddress)
|
||||
{
|
||||
voicePromptsDataHeader_t* header = (voicePromptsDataHeader_t*)bufferAddress;
|
||||
|
||||
return ((header->magic == VOICE_PROMPTS_DATA_MAGIC) &&
|
||||
(header->version == VOICE_PROMPTS_DATA_VERSION));
|
||||
}
|
||||
|
||||
void vp_init(void)
|
||||
{
|
||||
voicePromptsDataHeader_t header;
|
||||
vpDataOffset=0;
|
||||
|
||||
|
||||
if (!voice_prompt_file)
|
||||
vp_open(NULL);
|
||||
|
||||
|
||||
if (!voice_prompt_file)
|
||||
return;
|
||||
|
||||
|
||||
fseek(voice_prompt_file, 0L, SEEK_SET);
|
||||
fread((void*)&header, sizeof(header), 1, voice_prompt_file);
|
||||
|
||||
|
@ -141,26 +157,20 @@ void vpCacheInit(void)
|
|||
codec_init();
|
||||
}
|
||||
|
||||
bool vpCheckHeader(uint32_t* bufferAddress)
|
||||
{
|
||||
voicePromptsDataHeader_t* header = (voicePromptsDataHeader_t*)bufferAddress;
|
||||
|
||||
return ((header->magic == VOICE_PROMPTS_DATA_MAGIC) &&
|
||||
(header->version == VOICE_PROMPTS_DATA_VERSION));
|
||||
}
|
||||
|
||||
static void GetCodec2Data(int offset, int length)
|
||||
{
|
||||
if (!voice_prompt_file || (vpDataOffset < (sizeof(voicePromptsDataHeader_t) + sizeof(tableOfContents))))
|
||||
return;
|
||||
|
||||
|
||||
if ((offset < 0) || (length > Codec2DataBufferSize))
|
||||
return;
|
||||
|
||||
// Skip codec2 header
|
||||
fseek(voice_prompt_file, vpDataOffset+offset+CODEC2_HEADER_SIZE, SEEK_SET);
|
||||
fread((void*)&Codec2Data, length, 1, voice_prompt_file);
|
||||
// zero buffer from length to the next multiple of 8 to avoid garbage
|
||||
// zero buffer from length to the next multiple of 8 to avoid garbage
|
||||
// being played back, since codec2 frames are pushed in lots of 8 bytes.
|
||||
if ((length % 8) != 0)
|
||||
{
|
||||
|
@ -169,7 +179,7 @@ static void GetCodec2Data(int offset, int length)
|
|||
}
|
||||
}
|
||||
|
||||
void vpTerminate(void)
|
||||
void vp_terminate(void)
|
||||
{
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
|
@ -182,7 +192,7 @@ void vpTerminate(void)
|
|||
}
|
||||
}
|
||||
|
||||
void vpInit(void)
|
||||
void vp_clearCurrPrompt(void)
|
||||
{
|
||||
vpCurrentSequence.length = 0;
|
||||
vpCurrentSequence.pos = 0;
|
||||
|
@ -190,13 +200,13 @@ void vpInit(void)
|
|||
vpCurrentSequence.codec2DataLength = 0;
|
||||
}
|
||||
|
||||
void vpQueuePrompt(uint16_t prompt)
|
||||
void vp_queuePrompt(const uint16_t prompt)
|
||||
{
|
||||
if (state.settings.vpLevel < vpLow) return;
|
||||
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
}
|
||||
if (vpCurrentSequence.length < VOICE_PROMPTS_SEQUENCE_BUFFER_SIZE)
|
||||
{
|
||||
|
@ -254,13 +264,13 @@ static bool GetSymbolVPIfItShouldBeAnnounced(char symbol,
|
|||
}
|
||||
|
||||
// This function spells out a string letter by letter.
|
||||
void vpQueueString(char* promptString, VoicePromptFlags_T flags)
|
||||
void vp_queueString(char* promptString, VoicePromptFlags_T flags)
|
||||
{
|
||||
if (state.settings.vpLevel < vpLow) return;
|
||||
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
}
|
||||
|
||||
if (state.settings.vpPhoneticSpell) flags |= vpAnnouncePhoneticRendering;
|
||||
|
@ -270,70 +280,70 @@ void vpQueueString(char* promptString, VoicePromptFlags_T flags)
|
|||
voicePrompt_t vp = UserDictLookup(promptString, &advanceBy);
|
||||
if (vp)
|
||||
{
|
||||
vpQueuePrompt(vp);
|
||||
vp_queuePrompt(vp);
|
||||
promptString += advanceBy;
|
||||
continue;
|
||||
}
|
||||
else if ((*promptString >= '0') && (*promptString <= '9'))
|
||||
{
|
||||
vpQueuePrompt(*promptString - '0' + PROMPT_0);
|
||||
vp_queuePrompt(*promptString - '0' + PROMPT_0);
|
||||
}
|
||||
else if ((*promptString >= 'A') && (*promptString <= 'Z'))
|
||||
{
|
||||
if (flags & vpAnnounceCaps) vpQueuePrompt(PROMPT_CAP);
|
||||
if (flags & vpAnnounceCaps) vp_queuePrompt(PROMPT_CAP);
|
||||
if (flags & vpAnnouncePhoneticRendering)
|
||||
vpQueuePrompt((*promptString - 'A') + PROMPT_A_PHONETIC);
|
||||
vp_queuePrompt((*promptString - 'A') + PROMPT_A_PHONETIC);
|
||||
else
|
||||
vpQueuePrompt(*promptString - 'A' + PROMPT_A);
|
||||
vp_queuePrompt(*promptString - 'A' + PROMPT_A);
|
||||
}
|
||||
else if ((*promptString >= 'a') && (*promptString <= 'z'))
|
||||
{
|
||||
if (flags & vpAnnouncePhoneticRendering)
|
||||
vpQueuePrompt((*promptString - 'a') + PROMPT_A_PHONETIC);
|
||||
vp_queuePrompt((*promptString - 'a') + PROMPT_A_PHONETIC);
|
||||
else
|
||||
vpQueuePrompt(*promptString - 'a' + PROMPT_A);
|
||||
vp_queuePrompt(*promptString - 'a' + PROMPT_A);
|
||||
}
|
||||
else if ((*promptString == ' ') && (flags & vpAnnounceSpace))
|
||||
{
|
||||
vpQueuePrompt(PROMPT_SPACE);
|
||||
vp_queuePrompt(PROMPT_SPACE);
|
||||
}
|
||||
else if (GetSymbolVPIfItShouldBeAnnounced(*promptString, flags, &vp))
|
||||
{
|
||||
if (vp != PROMPT_SILENCE)
|
||||
vpQueuePrompt(vp);
|
||||
vp_queuePrompt(vp);
|
||||
else // announce ASCII
|
||||
{
|
||||
int32_t val = *promptString;
|
||||
vpQueuePrompt(PROMPT_CHARACTER); // just the word "code" as we
|
||||
vp_queuePrompt(PROMPT_CHARACTER); // just the word "code" as we
|
||||
// don't have character.
|
||||
vpQueueInteger(val);
|
||||
vp_queueInteger(val);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise just add silence
|
||||
vpQueuePrompt(PROMPT_SILENCE);
|
||||
vp_queuePrompt(PROMPT_SILENCE);
|
||||
}
|
||||
|
||||
promptString++;
|
||||
}
|
||||
if (flags & vpqAddSeparatingSilence) vpQueuePrompt(PROMPT_SILENCE);
|
||||
if (flags & vpqAddSeparatingSilence) vp_queuePrompt(PROMPT_SILENCE);
|
||||
}
|
||||
|
||||
void vpQueueInteger(int32_t value)
|
||||
void vp_queueInteger(const int32_t value)
|
||||
{
|
||||
if (state.settings.vpLevel < vpLow) return;
|
||||
|
||||
char buf[12] = {0}; // min: -2147483648, max: 2147483647
|
||||
snprintf(buf, 12, "%d", value);
|
||||
vpQueueString(buf, 0);
|
||||
vp_queueString(buf, 0);
|
||||
}
|
||||
|
||||
// This function looks up a voice prompt corresponding to a string table entry.
|
||||
// These are stored in the voice data after the voice prompts with no
|
||||
// corresponding string table entry, hence the offset calculation:
|
||||
// NUM_VOICE_PROMPTS + (stringTableStringPtr - currentLanguage->languageName)
|
||||
void vpQueueStringTableEntry(const char* const* stringTableStringPtr)
|
||||
void vp_queueStringTableEntry(const char* const* stringTableStringPtr)
|
||||
{
|
||||
if (state.settings.vpLevel < vpLow) return;
|
||||
|
||||
|
@ -341,31 +351,31 @@ void vpQueueStringTableEntry(const char* const* stringTableStringPtr)
|
|||
{
|
||||
return;
|
||||
}
|
||||
vpQueuePrompt(NUM_VOICE_PROMPTS + 1 +
|
||||
vp_queuePrompt(NUM_VOICE_PROMPTS + 1 +
|
||||
(stringTableStringPtr - ¤tLanguage->languageName)
|
||||
/ sizeof(const char *));
|
||||
}
|
||||
|
||||
void vpPlay(void)
|
||||
void vp_play(void)
|
||||
{
|
||||
if (state.settings.vpLevel < vpLow) return;
|
||||
|
||||
if (voicePromptIsActive) return;
|
||||
|
||||
|
||||
if (vpCurrentSequence.length <= 0) return;
|
||||
|
||||
|
||||
voicePromptIsActive = true; // Start the playback
|
||||
|
||||
|
||||
codec_startDecode(SINK_SPK);
|
||||
|
||||
|
||||
audio_enableAmp();
|
||||
}
|
||||
|
||||
// Call this from the main timer thread to continue voice prompt playback.
|
||||
void vpTick()
|
||||
void vp_tick()
|
||||
{
|
||||
if (!voicePromptIsActive) return;
|
||||
|
||||
|
||||
while (vpCurrentSequence.pos < vpCurrentSequence.length)
|
||||
{// get the codec2 data for the current prompt if needed.
|
||||
if (vpCurrentSequence.codec2DataLength == 0)
|
||||
|
@ -374,16 +384,16 @@ void vpTick()
|
|||
|
||||
vpCurrentSequence.codec2DataLength =
|
||||
tableOfContents[promptNumber + 1] - tableOfContents[promptNumber];
|
||||
|
||||
|
||||
GetCodec2Data(tableOfContents[promptNumber], vpCurrentSequence.codec2DataLength);
|
||||
|
||||
|
||||
vpCurrentSequence.codec2DataIndex = 0;
|
||||
}
|
||||
// push the codec2 data in lots of 8 byte frames.
|
||||
while (vpCurrentSequence.codec2DataIndex < vpCurrentSequence.codec2DataLength)
|
||||
{
|
||||
if (!codec_pushFrame(Codec2Data+vpCurrentSequence.codec2DataIndex, false))
|
||||
return; // wait until there is room, perhaps next vpTick call.
|
||||
return; // wait until there is room, perhaps next vp_tick call.
|
||||
vpCurrentSequence.codec2DataIndex += 8;
|
||||
}
|
||||
|
||||
|
@ -396,12 +406,12 @@ void vpTick()
|
|||
voicePromptIsActive=false;
|
||||
}
|
||||
|
||||
inline bool vpIsPlaying(void)
|
||||
bool vp_isPlaying(void)
|
||||
{
|
||||
return voicePromptIsActive;
|
||||
}
|
||||
|
||||
bool vpHasDataToPlay(void)
|
||||
bool vp_sequenceNotEmpty(void)
|
||||
{
|
||||
return (vpCurrentSequence.length > 0);
|
||||
}
|
||||
|
|
|
@ -616,7 +616,7 @@ int _ui_fsm_loadChannel(int16_t channel_index, bool *sync_rtx) {
|
|||
|
||||
void _ui_fsm_confirmVFOInput(bool *sync_rtx)
|
||||
{
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
// Switch to TX input
|
||||
if(ui_state.input_set == SET_RX)
|
||||
{
|
||||
|
@ -653,7 +653,7 @@ void _ui_fsm_confirmVFOInput(bool *sync_rtx)
|
|||
announceError(vpqInit);
|
||||
state.ui_screen = MAIN_VFO;
|
||||
}
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
|
||||
|
@ -661,14 +661,14 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
|
|||
// Advance input position
|
||||
ui_state.input_position += 1;
|
||||
// clear any prompts in progress.
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
// Save pressed number to calculate frequency and show in GUI
|
||||
ui_state.input_number = input_getPressedNumber(msg);
|
||||
// queue the digit just pressed.
|
||||
vpQueueInteger(ui_state.input_number);
|
||||
vp_queueInteger(ui_state.input_number);
|
||||
// queue point if user has entered three digits.
|
||||
if (ui_state.input_position==3)
|
||||
vpQueuePrompt(PROMPT_POINT);
|
||||
vp_queuePrompt(PROMPT_POINT);
|
||||
|
||||
if(ui_state.input_set == SET_RX)
|
||||
{
|
||||
|
@ -681,7 +681,7 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
|
|||
{// queue the rx freq just completed.
|
||||
vpQueueFrequency(ui_state.new_rx_frequency);
|
||||
/// now queue tx as user has changed fields.
|
||||
vpQueuePrompt(PROMPT_TRANSMIT);
|
||||
vp_queuePrompt(PROMPT_TRANSMIT);
|
||||
// Switch to TX input
|
||||
ui_state.input_set = SET_TX;
|
||||
// Reset input position
|
||||
|
@ -712,7 +712,7 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
|
|||
state.ui_screen = MAIN_VFO;
|
||||
}
|
||||
}
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void _ui_changeBrightness(int variation)
|
||||
|
|
|
@ -99,9 +99,9 @@ static void announceMenuItemIfNeeded(char* name, char* value)
|
|||
// See if we are already in the middle of speaking a menu item.
|
||||
// e.g. when changing a value with left or right, we don't want to repeat the
|
||||
// prompt if arrowing rapidly.
|
||||
bool voicePromptWasPlaying=vpIsPlaying();
|
||||
bool voicePromptWasPlaying=vp_isPlaying();
|
||||
// Stop any prompt in progress and clear the buffer.
|
||||
vpInit();
|
||||
vp_clearCurrPrompt();
|
||||
// If no value is supplied, or, no prompt is in progress, announce the name.
|
||||
if (!voicePromptWasPlaying || !value || !*value)
|
||||
announceText(name, vpqDefault);
|
||||
|
@ -109,7 +109,7 @@ static void announceMenuItemIfNeeded(char* name, char* value)
|
|||
if (value && *value)
|
||||
announceText(value, vpqDefault);
|
||||
|
||||
vpPlay();
|
||||
vp_play();
|
||||
}
|
||||
|
||||
void _ui_drawMenuList(uint8_t selected, int (*getCurrentEntry)(char *buf, uint8_t max_len, uint8_t index))
|
||||
|
|
|
@ -34,12 +34,12 @@ int main()
|
|||
state.settings.vpLevel = 3;
|
||||
VoicePromptQueueFlags_T flags = GetQueueFlagsForVoiceLevel();
|
||||
|
||||
vpCacheInit();
|
||||
vpInit();
|
||||
vpQueueStringTableEntry(¤tLanguage->allChannels);
|
||||
vpPlay();
|
||||
vp_init();
|
||||
vp_clearCurrPrompt();
|
||||
vp_queueStringTableEntry(¤tLanguage->allChannels);
|
||||
vp_play();
|
||||
while(true)
|
||||
{
|
||||
vpTick();
|
||||
vp_tick();
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue