arduino-simple-tts
Loading...
Searching...
No Matches
NumberUnitToText.h
1#pragma once
2#include "NumberToText.h"
3
4namespace simple_tts {
5
14 public:
15 // Default constructor with no default unit
16 NumberUnitToText() = default;
17
18 // Constructor which assigns a default uinit so that we do not need to provide
19 // it
20 NumberUnitToText(const char* defaultUnit) { default_unit = defaultUnit; }
21
23 audio_tools::Vector<const char*>& say(double value,
24 const char* unit = nullptr,
25 int decimals = 2) {
26 Number number;
27 number.set(value, decimals);
28 return say(number.intValue(), number.decValues(), unit);
29 }
30
32 audio_tools::Vector<const char*>& say(int64_t wholeNumber,
33 const char* unit = nullptr) {
34 Number number;
35 number.set(wholeNumber);
36 return say(number.intValue(), number.decValues(), unit);
37 }
38
40 audio_tools::Vector<const char*>& say(const char* wholeNumber,
41 const char* decimals,
42 const char* unitIn) {
43 result.clear();
44
45 // determine unit
46 const char* unit = unitIn ? unitIn : default_unit;
47 // singular or plural ?
48 bool isOne = Str(wholeNumber).toLong() == 1l;
49
50 // We support 2 scenarios: combined units or just a smple number with a single unit.
51 int idx = idxCombinedUnit(unit);
52 if (idx == -1) {
53 // Simple units scenario
54 addAll(ntt.say(wholeNumber, decimals));
55 process(unit, isOne);
56 } else {
57 // Combined units ->
58 // say the wholeNumber first
59 addAll(ntt.say(wholeNumber));
60 // say whole number unit
61 processCombinedUnit(idx, isOne);
62 // combine them with AND
63 add("AND");
64 // say converted decimals
65 Number calc;
66 int digits = decimalInfo(unit);
67 const char* decimals_to_say = calc.decAsInt(decimals, digits);
68 addAll(ntt.say(decimals_to_say));
69 // say decimals unit
70 bool decIsOne = Str(decimals).toLong() == 1l;
71 processDecimalUnit(idx, decIsOne);
72 }
73
74 // provide result to callback
75 if (callback){
76 callback(result, reference);
77 }
78
79 return result;
80 }
81
83 virtual audio_tools::Vector<const char*>& allTexts() {
84 result.clear();
85
86 // add words from unit_1
87 for (int j = 0; j < max_unit_1; j++) {
88 add(unit_1[j][1]);
89 add(unit_1[j][2]);
90 }
91
92 // add words form unit_3
93 for (int j = 0; j < max_unit_2; j++) {
94 for (int i = 1; i < 4; i++) {
95 const char* word = unit2[j][i];
96 if (word != nullptr) {
97 if (!isKey(word)) {
98 add(word);
99 }
100 }
101 }
102 }
103
104 return result;
105 }
106
107 protected:
108 const char* default_unit = nullptr;
109 audio_tools::Vector<const char*> result;
110 NumberToText ntt;
111
112 // units which can have singurlar and plural
113 const static int max_unit_1 = 6;
114 const char* unit_1[max_unit_1][3] = {
115 {"lb", "pound", "pounds"}, {"ft", "foot", "feet"},
116 {"in", "inch", "inches"}, {"mi", "mile", "miles"},
117 {"$", "dollar", "dollars"}, {"¢", "cent", "cents"}};
118
120 const static int max_unit_2 = 15;
121 const char* unit2[max_unit_2][4] = {{"mph", "miles", "per", "hour"},
122 {"C", "degrees", "celcius", nullptr},
123 {"F", "degrees", "fahrenheit", nullptr},
124 {"%", "percent", nullptr, nullptr},
125 {"lt", "liter", nullptr, nullptr},
126 {"ml", "milli", "lt", nullptr},
127 {"gr", "gram", nullptr, nullptr},
128 {"kg", "kilo", "gr", nullptr},
129 {"mg", "milli", "gr", nullptr},
130 {"km", "kilo", "m", nullptr},
131 {"m", "meter", nullptr, nullptr},
132 {"cm", "centi", "m", nullptr},
133 {"mm", "milli", "m", nullptr},
134 {"u.s.", "us", nullptr, nullptr},
135 {"usd", "u.s.", "$", nullptr}};
136
137 // split unit before and after the decimal point: 1.20 USD is 1 dollar and 20
138 // cents
139 const static int max_unit_3 = 6;
140 const char* unit3[max_unit_3][2] = {{"usd", "¢"}, {"gr", "mg"}, {"kg", "gr"},
141 {"m", "mm"}, {"km", "m"}, {"lt", "ml"}};
142
144 struct DecimalInfo {
145 const char* id;
146 int dec;
147 };
148 const static int decimal_info_len = 1;
149 const DecimalInfo decimal_info[decimal_info_len] = {{"usd", 2}};
150
151 // add a single word to the result
152 void add(const char* str) { result.push_back(str); }
153
154 // add a list to the result
155 void addAll(audio_tools::Vector<const char*>& words) {
156 for (auto word : words) {
157 add(word);
158 }
159 }
160
162 bool process(const char* unit, bool isOne) {
163 if (!isKey(unit)) {
164 add(unit);
165 return true;
166 }
167 // check in table1 first
168 if (process1(unit, isOne)) return true;
169 // process table 2
170 if (process2(unit, isOne)) return true;
171 // last resort use the unit directly
172 if (!isKey(unit)) {
173 LOGE("Error %s", unit);
174 }
175 return false;
176 }
177
178 bool process2(const char* unit, bool isOne) {
179 // process table 2
180 bool result = false;
181 Str u(unit);
182 for (int j = 0; j < max_unit_2; j++) {
183 if (u.equalsIgnoreCase(unit2[j][0])) {
184 for (int i = 1; i < 4; i++) {
185 const char* word = unit2[j][i];
186 if (word != nullptr) {
187 if (!isKey(word)) {
188 add(word);
189 result = true;
190 } else {
191 if (process(word, isOne)) {
192 result = true;
193 }
194 }
195 }
196 }
197 }
198 }
199 return result;
200 }
201
202 bool process1(const char* unit, bool isOne) {
203 Str u(unit);
204 for (int j = 0; j < max_unit_1; j++) {
205 if (u.equalsIgnoreCase(unit_1[j][0])) {
206 // determine singular or plural
207 add(isOne ? unit_1[j][1] : unit_1[j][2]);
208 return true;
209 }
210 }
211 return false;
212 }
213
214 bool isKey(const char* unit) {
215 Str u(unit);
216 for (int j = 0; j < max_unit_1; j++) {
217 if (u.equalsIgnoreCase(unit_1[j][0])) {
218 return true;
219 }
220 }
221
222 for (int j = 0; j < max_unit_2; j++) {
223 if (u.equalsIgnoreCase(unit2[j][0])) {
224 return true;
225 }
226 }
227 return false;
228 }
229
230 // checks if this is a combined unit (part of unit3) where we need to
231 // separate the integers from the decimals with a different unit
232 int idxCombinedUnit(const char* unit) {
233 Str u(unit);
234 for (int i = 0; i < max_unit_3; i++) {
235 if (u.equalsIgnoreCase(unit3[i][0])) {
236 return i;
237 }
238 }
239 return -1;
240 }
241
242 bool processCombinedUnit(int idx, bool isOne) {
243 return process(unit3[idx][0], isOne);
244 }
245
246 bool processDecimalUnit(int idx, bool isOne) {
247 return process(unit3[idx][1], isOne);
248 }
249
250 int decimalInfo(const char* unit) {
251 Str u(unit);
252 for (int i = 0; i < decimal_info_len; i++) {
253 if (u.equalsIgnoreCase(decimal_info[i].id)) {
254 return decimal_info[i].dec;
255 }
256 }
257 // all metric units are based on 1000
258 return 3;
259 }
260};
261
262} // namespace simple_tts
Convert numbers to string and provide integer and decimals.
Definition: SimpleTTSBase.h:106
const char * intValue()
provides the full number
Definition: SimpleTTSBase.h:139
const char * decValues()
provides the decimals after the .
Definition: SimpleTTSBase.h:144
Translates a number into englich words.
Definition: NumberToText.h:15
audio_tools::Vector< const char * > & say(double value, int decimals=2)
converts a real number to it's text representation (with the indicated number of digits)
Definition: NumberToText.h:19
An extension of the Number to Text functionality which supports numbers with units of measures.
Definition: NumberUnitToText.h:13
audio_tools::Vector< const char * > & say(int64_t wholeNumber, const char *unit=nullptr)
converts an integer with a unit to it's text representation
Definition: NumberUnitToText.h:32
bool process(const char *unit, bool isOne)
resolve keys until we end up with final words
Definition: NumberUnitToText.h:162
audio_tools::Vector< const char * > & say(double value, const char *unit=nullptr, int decimals=2)
converts a real number with a unit to it's text representation
Definition: NumberUnitToText.h:23
static const int max_unit_2
units that can be constructed by combining words
Definition: NumberUnitToText.h:120
audio_tools::Vector< const char * > & say(const char *wholeNumber, const char *decimals, const char *unitIn)
converts a number provided by string components to it's text representation
Definition: NumberUnitToText.h:40
virtual audio_tools::Vector< const char * > & allTexts()
Provides all texts.
Definition: NumberUnitToText.h:83
Common Functionality for TTS classes.
Definition: SimpleTTSBase.h:15
Units might have different decimals. The decimal system is based on 3. But currencies have usually 2.
Definition: NumberUnitToText.h:144