Various fixes around Companion trainer mode (#7116)
[opentx.git] / radio / src / audio.cpp
blobc8417568d34739bf96972d01bb1aeb80acf8f8cb
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
22 #include <math.h>
24 extern RTOS_MUTEX_HANDLE audioMutex;
26 const int16_t sineValues[] =
28 0, 196, 392, 588, 784, 980, 1175, 1370, 1564, 1758,
29 1951, 2143, 2335, 2525, 2715, 2904, 3091, 3278, 3463, 3647,
30 3829, 4011, 4190, 4369, 4545, 4720, 4894, 5065, 5235, 5403,
31 5569, 5733, 5895, 6055, 6213, 6369, 6522, 6673, 6822, 6969,
32 7113, 7255, 7395, 7532, 7667, 7799, 7929, 8056, 8180, 8302,
33 8422, 8539, 8653, 8765, 8874, 8980, 9084, 9185, 9283, 9379,
34 9472, 9562, 9650, 9735, 9818, 9898, 9975, 10050, 10123, 10192,
35 10260, 10324, 10387, 10447, 10504, 10559, 10612, 10663, 10711, 10757,
36 10801, 10843, 10882, 10920, 10955, 10989, 11020, 11050, 11078, 11104,
37 11128, 11151, 11172, 11191, 11209, 11225, 11240, 11254, 11266, 11277,
38 11287, 11296, 11303, 11310, 11316, 11320, 11324, 11327, 11330, 11331,
39 11332, 11333, 11333, 11333, 11332, 11331, 11329, 11328, 11326, 11324,
40 11323, 11321, 11319, 11318, 11316, 11315, 11314, 11313, 11313, 11313,
41 11314, 11315, 11317, 11319, 11323, 11326, 11331, 11336, 11342, 11349,
42 11356, 11365, 11375, 11385, 11397, 11409, 11423, 11437, 11453, 11470,
43 11488, 11507, 11527, 11548, 11571, 11595, 11620, 11646, 11673, 11702,
44 11732, 11763, 11795, 11828, 11863, 11899, 11936, 11974, 12013, 12054,
45 12095, 12138, 12182, 12227, 12273, 12320, 12368, 12417, 12467, 12518,
46 12570, 12623, 12676, 12731, 12786, 12842, 12898, 12956, 13014, 13072,
47 13131, 13191, 13251, 13311, 13372, 13433, 13495, 13556, 13618, 13680,
48 13743, 13805, 13867, 13929, 13991, 14053, 14115, 14177, 14238, 14299,
49 14359, 14419, 14479, 14538, 14597, 14655, 14712, 14768, 14824, 14879,
50 14933, 14986, 15039, 15090, 15140, 15189, 15237, 15284, 15330, 15375,
51 15418, 15460, 15500, 15539, 15577, 15614, 15648, 15682, 15714, 15744,
52 15772, 15799, 15825, 15849, 15871, 15891, 15910, 15927, 15942, 15955,
53 15967, 15977, 15985, 15991, 15996, 15999, 16000, 15999, 15996, 15991,
54 15985, 15977, 15967, 15955, 15942, 15927, 15910, 15891, 15871, 15849,
55 15825, 15799, 15772, 15744, 15714, 15682, 15648, 15614, 15577, 15539,
56 15500, 15460, 15418, 15375, 15330, 15284, 15237, 15189, 15140, 15090,
57 15039, 14986, 14933, 14879, 14824, 14768, 14712, 14655, 14597, 14538,
58 14479, 14419, 14359, 14299, 14238, 14177, 14115, 14053, 13991, 13929,
59 13867, 13805, 13743, 13680, 13618, 13556, 13495, 13433, 13372, 13311,
60 13251, 13191, 13131, 13072, 13014, 12956, 12898, 12842, 12786, 12731,
61 12676, 12623, 12570, 12518, 12467, 12417, 12368, 12320, 12273, 12227,
62 12182, 12138, 12095, 12054, 12013, 11974, 11936, 11899, 11863, 11828,
63 11795, 11763, 11732, 11702, 11673, 11646, 11620, 11595, 11571, 11548,
64 11527, 11507, 11488, 11470, 11453, 11437, 11423, 11409, 11397, 11385,
65 11375, 11365, 11356, 11349, 11342, 11336, 11331, 11326, 11323, 11319,
66 11317, 11315, 11314, 11313, 11313, 11313, 11314, 11315, 11316, 11318,
67 11319, 11321, 11323, 11324, 11326, 11328, 11329, 11331, 11332, 11333,
68 11333, 11333, 11332, 11331, 11330, 11327, 11324, 11320, 11316, 11310,
69 11303, 11296, 11287, 11277, 11266, 11254, 11240, 11225, 11209, 11191,
70 11172, 11151, 11128, 11104, 11078, 11050, 11020, 10989, 10955, 10920,
71 10882, 10843, 10801, 10757, 10711, 10663, 10612, 10559, 10504, 10447,
72 10387, 10324, 10260, 10192, 10123, 10050, 9975, 9898, 9818, 9735,
73 9650, 9562, 9472, 9379, 9283, 9185, 9084, 8980, 8874, 8765,
74 8653, 8539, 8422, 8302, 8180, 8056, 7929, 7799, 7667, 7532,
75 7395, 7255, 7113, 6969, 6822, 6673, 6522, 6369, 6213, 6055,
76 5895, 5733, 5569, 5403, 5235, 5065, 4894, 4720, 4545, 4369,
77 4190, 4011, 3829, 3647, 3463, 3278, 3091, 2904, 2715, 2525,
78 2335, 2143, 1951, 1758, 1564, 1370, 1175, 980, 784, 588,
79 392, 196, 0, -196, -392, -588, -784, -980, -1175, -1370,
80 -1564, -1758, -1951, -2143, -2335, -2525, -2715, -2904, -3091, -3278,
81 -3463, -3647, -3829, -4011, -4190, -4369, -4545, -4720, -4894, -5065,
82 -5235, -5403, -5569, -5733, -5895, -6055, -6213, -6369, -6522, -6673,
83 -6822, -6969, -7113, -7255, -7395, -7532, -7667, -7799, -7929, -8056,
84 -8180, -8302, -8422, -8539, -8653, -8765, -8874, -8980, -9084, -9185,
85 -9283, -9379, -9472, -9562, -9650, -9735, -9818, -9898, -9975, -10050,
86 -10123, -10192, -10260, -10324, -10387, -10447, -10504, -10559, -10612, -10663,
87 -10711, -10757, -10801, -10843, -10882, -10920, -10955, -10989, -11020, -11050,
88 -11078, -11104, -11128, -11151, -11172, -11191, -11209, -11225, -11240, -11254,
89 -11266, -11277, -11287, -11296, -11303, -11310, -11316, -11320, -11324, -11327,
90 -11330, -11331, -11332, -11333, -11333, -11333, -11332, -11331, -11329, -11328,
91 -11326, -11324, -11323, -11321, -11319, -11318, -11316, -11315, -11314, -11313,
92 -11313, -11313, -11314, -11315, -11317, -11319, -11323, -11326, -11331, -11336,
93 -11342, -11349, -11356, -11365, -11375, -11385, -11397, -11409, -11423, -11437,
94 -11453, -11470, -11488, -11507, -11527, -11548, -11571, -11595, -11620, -11646,
95 -11673, -11702, -11732, -11763, -11795, -11828, -11863, -11899, -11936, -11974,
96 -12013, -12054, -12095, -12138, -12182, -12227, -12273, -12320, -12368, -12417,
97 -12467, -12518, -12570, -12623, -12676, -12731, -12786, -12842, -12898, -12956,
98 -13014, -13072, -13131, -13191, -13251, -13311, -13372, -13433, -13495, -13556,
99 -13618, -13680, -13743, -13805, -13867, -13929, -13991, -14053, -14115, -14177,
100 -14238, -14299, -14359, -14419, -14479, -14538, -14597, -14655, -14712, -14768,
101 -14824, -14879, -14933, -14986, -15039, -15090, -15140, -15189, -15237, -15284,
102 -15330, -15375, -15418, -15460, -15500, -15539, -15577, -15614, -15648, -15682,
103 -15714, -15744, -15772, -15799, -15825, -15849, -15871, -15891, -15910, -15927,
104 -15942, -15955, -15967, -15977, -15985, -15991, -15996, -15999, -16000, -15999,
105 -15996, -15991, -15985, -15977, -15967, -15955, -15942, -15927, -15910, -15891,
106 -15871, -15849, -15825, -15799, -15772, -15744, -15714, -15682, -15648, -15614,
107 -15577, -15539, -15500, -15460, -15418, -15375, -15330, -15284, -15237, -15189,
108 -15140, -15090, -15039, -14986, -14933, -14879, -14824, -14768, -14712, -14655,
109 -14597, -14538, -14479, -14419, -14359, -14299, -14238, -14177, -14115, -14053,
110 -13991, -13929, -13867, -13805, -13743, -13680, -13618, -13556, -13495, -13433,
111 -13372, -13311, -13251, -13191, -13131, -13072, -13014, -12956, -12898, -12842,
112 -12786, -12731, -12676, -12623, -12570, -12518, -12467, -12417, -12368, -12320,
113 -12273, -12227, -12182, -12138, -12095, -12054, -12013, -11974, -11936, -11899,
114 -11863, -11828, -11795, -11763, -11732, -11702, -11673, -11646, -11620, -11595,
115 -11571, -11548, -11527, -11507, -11488, -11470, -11453, -11437, -11423, -11409,
116 -11397, -11385, -11375, -11365, -11356, -11349, -11342, -11336, -11331, -11326,
117 -11323, -11319, -11317, -11315, -11314, -11313, -11313, -11313, -11314, -11315,
118 -11316, -11318, -11319, -11321, -11323, -11324, -11326, -11328, -11329, -11331,
119 -11332, -11333, -11333, -11333, -11332, -11331, -11330, -11327, -11324, -11320,
120 -11316, -11310, -11303, -11296, -11287, -11277, -11266, -11254, -11240, -11225,
121 -11209, -11191, -11172, -11151, -11128, -11104, -11078, -11050, -11020, -10989,
122 -10955, -10920, -10882, -10843, -10801, -10757, -10711, -10663, -10612, -10559,
123 -10504, -10447, -10387, -10324, -10260, -10192, -10123, -10050, -9975, -9898,
124 -9818, -9735, -9650, -9562, -9472, -9379, -9283, -9185, -9084, -8980,
125 -8874, -8765, -8653, -8539, -8422, -8302, -8180, -8056, -7929, -7799,
126 -7667, -7532, -7395, -7255, -7113, -6969, -6822, -6673, -6522, -6369,
127 -6213, -6055, -5895, -5733, -5569, -5403, -5235, -5065, -4894, -4720,
128 -4545, -4369, -4190, -4011, -3829, -3647, -3463, -3278, -3091, -2904,
129 -2715, -2525, -2335, -2143, -1951, -1758, -1564, -1370, -1175, -980,
130 -784, -588, -392, -196,
133 #if defined(SDCARD)
135 const char * const unitsFilenames[] = {
137 "volt",
138 "amp",
139 "mamp",
140 "knot",
141 "mps",
142 "fps",
143 "kph",
144 "mph",
145 "meter",
146 "foot",
147 "celsius",
148 "fahr",
149 "percent",
150 "mamph",
151 "watt",
152 "mwatt",
153 "db",
154 "rpm",
155 "g",
156 "degree",
157 "radian",
158 "ml",
159 "founce",
160 "mlpm",
161 "spare1",
162 "spare2",
163 "spare3",
164 "spare4",
165 "spare5",
166 "spare6",
167 "spare7",
168 "spare8",
169 "spare9",
170 "spare10",
171 "hour",
172 "minute",
173 "second",
176 const char * const audioFilenames[] = {
177 "hello",
178 "bye",
179 "thralert",
180 "swalert",
181 "baddata",
182 "lowbatt",
183 "inactiv",
184 "rssi_org",
185 "rssi_red",
186 "swr_red",
187 "telemko",
188 "telemok",
189 "trainko",
190 "trainok",
191 "sensorko",
192 "servoko",
193 "rxko",
194 "modelpwr",
195 #if defined(PCBSKY9X)
196 "highmah",
197 "hightemp",
198 #endif
199 "error",
200 "warning1",
201 "warning2",
202 "warning3",
203 "midtrim",
204 "mintrim",
205 "maxtrim",
206 "midstck1",
207 "midstck2",
208 "midstck3",
209 "midstck4",
210 #if defined(PCBTARANIS) || defined(PCBHORUS)
211 "midpot1",
212 "midpot2",
213 #if defined(PCBX9E)
214 "midpot3",
215 "midpot4",
216 #endif
217 "midslid1",
218 "midslid2",
219 #if defined(PCBX9E)
220 "midslid3",
221 "midslid4",
222 #endif
223 #else
224 "midpot1",
225 "midpot2",
226 "midpot3",
227 #endif
228 "mixwarn1",
229 "mixwarn2",
230 "mixwarn3",
231 "timovr1",
232 "timovr2",
233 "timovr3"
236 BitField<(AU_SPECIAL_SOUND_FIRST)> sdAvailableSystemAudioFiles;
237 BitField<(MAX_FLIGHT_MODES * 2/*on, off*/)> sdAvailableFlightmodeAudioFiles;
238 BitField<(SWSRC_LAST_SWITCH+NUM_XPOTS*XPOTS_MULTIPOS_COUNT)> sdAvailableSwitchAudioFiles;
239 BitField<(MAX_LOGICAL_SWITCHES * 2/*on, off*/)> sdAvailableLogicalSwitchAudioFiles;
241 char * getAudioPath(char * path)
243 strcpy(path, SOUNDS_PATH "/");
244 strncpy(path+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
245 return path + sizeof(SOUNDS_PATH);
248 char * strAppendSystemAudioPath(char * path)
250 char * str = getAudioPath(path);
251 strcpy(str, SYSTEM_SUBDIR "/");
252 return str + sizeof(SYSTEM_SUBDIR);
255 void getSystemAudioFile(char * filename, int index)
257 char * str = strAppendSystemAudioPath(filename);
258 strcpy(str, audioFilenames[index]);
259 strcat(str, SOUNDS_EXT);
262 void referenceSystemAudioFiles()
264 static_assert(sizeof(audioFilenames)==AU_SPECIAL_SOUND_FIRST*sizeof(char *), "Invalid audioFilenames size");
265 char path[AUDIO_FILENAME_MAXLEN+1];
266 FILINFO fno;
267 DIR dir;
269 sdAvailableSystemAudioFiles.reset();
271 char * filename = strAppendSystemAudioPath(path);
272 *(filename-1) = '\0';
274 FRESULT res = f_opendir(&dir, path); /* Open the directory */
275 if (res == FR_OK) {
276 for (;;) {
277 res = f_readdir(&dir, &fno); /* Read a directory item */
278 if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
279 uint8_t len = strlen(fno.fname);
281 // Eliminates directories / non wav files
282 if (len < 5 || strcasecmp(fno.fname+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue;
284 for (int i=0; i<AU_SPECIAL_SOUND_FIRST; i++) {
285 getSystemAudioFile(path, i);
286 if (!strcasecmp(filename, fno.fname)) {
287 sdAvailableSystemAudioFiles.setBit(i);
288 break;
292 f_closedir(&dir);
296 const char * const suffixes[] = { "-off", "-on" };
298 char * getModelAudioPath(char * path)
300 strcpy(path, SOUNDS_PATH "/");
301 strncpy(path+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2);
302 char * result = strcat_currentmodelname(path+sizeof(SOUNDS_PATH));
303 *result++ = '/';
304 *result = '\0';
305 return result;
308 void getFlightmodeAudioFile(char * filename, int index, unsigned int event)
310 char * str = getModelAudioPath(filename);
311 char * tmp = strcatFlightmodeName(str, index);
312 strcpy(tmp, suffixes[event]);
313 strcat(tmp, SOUNDS_EXT);
316 void getSwitchAudioFile(char * filename, swsrc_t index)
318 char * str = getModelAudioPath(filename);
320 #if defined(PCBTARANIS) || defined(PCBHORUS)
321 if (index <= SWSRC_LAST_SWITCH) {
322 div_t swinfo = switchInfo(index);
323 *str++ = 'S';
324 *str++ = 'A' + swinfo.quot;
325 const char * positions[] = { "-up", "-mid", "-down" };
326 strcpy(str, positions[swinfo.rem]);
328 else {
329 div_t swinfo = div(int(index - SWSRC_FIRST_MULTIPOS_SWITCH), XPOTS_MULTIPOS_COUNT);
330 *str++ = 'S';
331 *str++ = '1' + swinfo.quot;
332 *str++ = '1' + swinfo.rem;
333 *str = '\0';
335 #else
336 int len = STR_VSWITCHES[0];
337 strncpy(str, &STR_VSWITCHES[1+(len*index)], len);
338 str += len;
339 *str = '\0';
340 #endif
341 strcat(str, SOUNDS_EXT);
344 void getLogicalSwitchAudioFile(char * filename, int index, unsigned int event)
346 char * str = getModelAudioPath(filename);
348 #if defined(PCBTARANIS) || defined(PCBHORUS)
349 *str++ = 'L';
350 if (index >= 9) {
351 div_t qr = div(index+1, 10);
352 *str++ = '0' + qr.quot;
353 *str++ = '0' + qr.rem;
355 else {
356 *str++ = '1' + index;
358 #else
359 int len = STR_VSWITCHES[0];
360 strncpy(str, &STR_VSWITCHES[1+len*(index+SWSRC_FIRST_LOGICAL_SWITCH)], len);
361 str += len;
362 #endif
364 strcpy(str, suffixes[event]);
365 strcat(str, SOUNDS_EXT);
368 void referenceModelAudioFiles()
370 char path[AUDIO_FILENAME_MAXLEN+1];
371 FILINFO fno;
372 DIR dir;
374 sdAvailableFlightmodeAudioFiles.reset();
375 sdAvailableSwitchAudioFiles.reset();
376 sdAvailableLogicalSwitchAudioFiles.reset();
378 char * filename = getModelAudioPath(path);
379 *(filename-1) = '\0';
381 FRESULT res = f_opendir(&dir, path); /* Open the directory */
382 if (res == FR_OK) {
383 for (;;) {
384 res = f_readdir(&dir, &fno); /* Read a directory item */
385 if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
386 uint8_t len = strlen(fno.fname);
387 bool found = false;
389 // Eliminates directories / non wav files
390 if (len < 5 || strcasecmp(fno.fname+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue;
391 TRACE("referenceModelAudioFiles(): using file: %s", fno.fname);
393 // Flight modes Audio Files <flightmodename>-[on|off].wav
394 for (int i=0; i<MAX_FLIGHT_MODES && !found; i++) {
395 for (int event=0; event<2; event++) {
396 getFlightmodeAudioFile(path, i, event);
397 // TRACE("referenceModelAudioFiles(): searching for %s in %s", filename, fno.fname);
398 if (!strcasecmp(filename, fno.fname)) {
399 sdAvailableFlightmodeAudioFiles.setBit(INDEX_PHASE_AUDIO_FILE(i, event));
400 found = true;
401 TRACE("\tfound: %s", filename);
402 break;
407 // Switches Audio Files <switchname>-[up|mid|down].wav
408 for (int i=SWSRC_FIRST_SWITCH; i<=SWSRC_LAST_SWITCH+NUM_XPOTS*XPOTS_MULTIPOS_COUNT && !found; i++) {
409 getSwitchAudioFile(path, i);
410 // TRACE("referenceModelAudioFiles(): searching for %s in %s (%d)", path, fno.fname, i);
411 if (!strcasecmp(filename, fno.fname)) {
412 sdAvailableSwitchAudioFiles.setBit(i-SWSRC_FIRST_SWITCH);
413 found = true;
414 TRACE("\tfound: %s", filename);
418 // Logical Switches Audio Files <switchname>-[on|off].wav
419 for (int i=0; i<MAX_LOGICAL_SWITCHES && !found; i++) {
420 for (int event=0; event<2; event++) {
421 getLogicalSwitchAudioFile(path, i, event);
422 // TRACE("referenceModelAudioFiles(): searching for %s in %s", filename, fno.fname);
423 if (!strcasecmp(filename, fno.fname)) {
424 sdAvailableLogicalSwitchAudioFiles.setBit(INDEX_LOGICAL_SWITCH_AUDIO_FILE(i, event));
425 found = true;
426 TRACE("\tfound: %s", filename);
427 break;
432 f_closedir(&dir);
436 bool isAudioFileReferenced(uint32_t i, char * filename)
438 uint8_t category = (i >> 24);
439 uint8_t index = (i >> 16) & 0xFF;
440 event_t event = i & 0xFF;
442 // TRACE("isAudioFileReferenced(%08x)", i);
444 if (category == SYSTEM_AUDIO_CATEGORY) {
445 if (sdAvailableSystemAudioFiles.getBit(event)) {
446 getSystemAudioFile(filename, event);
447 return true;
450 else if (category == PHASE_AUDIO_CATEGORY) {
451 if (sdAvailableFlightmodeAudioFiles.getBit(INDEX_PHASE_AUDIO_FILE(index, event))) {
452 getFlightmodeAudioFile(filename, index, event);
453 return true;
456 else if (category == SWITCH_AUDIO_CATEGORY) {
457 if (sdAvailableSwitchAudioFiles.getBit(index)) {
458 getSwitchAudioFile(filename, SWSRC_FIRST_SWITCH+index);
459 return true;
462 else if (category == LOGICAL_SWITCH_AUDIO_CATEGORY) {
463 if (sdAvailableLogicalSwitchAudioFiles.getBit(INDEX_LOGICAL_SWITCH_AUDIO_FILE(index, event))) {
464 getLogicalSwitchAudioFile(filename, index, event);
465 return true;
469 return false;
472 tmr10ms_t timeAutomaticPromptsSilence = 0;
474 void playModelEvent(uint8_t category, uint8_t index, event_t event)
476 char filename[AUDIO_FILENAME_MAXLEN+1];
477 // TRACE("playModelEvent(): cat: %u, idx: %u, evt:%u", (uint32_t)category, (uint32_t)index, (uint32_t)event);
478 if (IS_SILENCE_PERIOD_ELAPSED() && isAudioFileReferenced((category << 24) + (index << 16) + event, filename)) {
479 audioQueue.playFile(filename);
483 void playModelName()
485 char filename[AUDIO_FILENAME_MAXLEN+1];
486 char * str = getModelAudioPath(filename);
487 strcpy(str, "name.wav");
488 audioQueue.playFile(filename);
491 #else // defined(SDCARD)
493 #define isAudioFileReferenced(i, f) false
495 #endif // defined(SDCARD)
497 const int16_t alawTable[256] = { -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344, -328, -376, -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848 };
498 const int16_t ulawTable[256] = { -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, -876, -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524, -492, -460, -428, -396, -372, -356, -340, -324, -308, -292, -276, -260, -244, -228, -212, -196, -180, -164, -148, -132, -120, -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 876, 844, 812, 780, 748, 716, 684, 652, 620, 588, 556, 524, 492, 460, 428, 396, 372, 356, 340, 324, 308, 292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0 };
500 AudioQueue audioQueue __DMA; // to place it in the RAM section on Horus, to have file buffers in RAM for DMA access
501 AudioBuffer audioBuffers[AUDIO_BUFFER_COUNT] __DMA;
503 AudioQueue::AudioQueue()
504 : buffersFifo(),
505 _started(false),
506 normalContext(),
507 backgroundContext(),
508 priorityContext(),
509 varioContext(),
510 fragmentsFifo()
514 #define CODEC_ID_PCM_S16LE 1
515 #define CODEC_ID_PCM_ALAW 6
516 #define CODEC_ID_PCM_MULAW 7
518 #if !defined(SIMU)
519 void audioTask(void * pdata)
521 while (!audioQueue.started()) {
522 RTOS_WAIT_TICKS(1);
525 setSampleRate(AUDIO_SAMPLE_RATE);
527 #if defined(PCBX12S)
528 // The audio amp needs ~2s to start
529 RTOS_WAIT_MS(1000); // 1s
530 #endif
532 if (!globalData.unexpectedShutdown) {
533 AUDIO_HELLO();
536 while (1) {
537 DEBUG_TIMER_SAMPLE(debugTimerAudioIterval);
538 DEBUG_TIMER_START(debugTimerAudioDuration);
539 audioQueue.wakeup();
540 DEBUG_TIMER_STOP(debugTimerAudioDuration);
541 RTOS_WAIT_MS(4);
544 #endif
546 inline void mixSample(audio_data_t * result, int sample, unsigned int fade)
548 *result = limit(AUDIO_DATA_MIN, *result + ((sample >> fade) >> (16-AUDIO_BITS_PER_SAMPLE)), AUDIO_DATA_MAX);
551 #if defined(SDCARD)
553 #define RIFF_CHUNK_SIZE 12
554 uint8_t wavBuffer[AUDIO_BUFFER_SIZE*2] __DMA;
556 int WavContext::mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade)
558 FRESULT result = FR_OK;
559 UINT read = 0;
561 if (fragment.file[1]) {
562 result = f_open(&state.file, fragment.file, FA_OPEN_EXISTING | FA_READ);
563 fragment.file[1] = 0;
564 if (result == FR_OK) {
565 result = f_read(&state.file, wavBuffer, RIFF_CHUNK_SIZE+8, &read);
566 if (result == FR_OK && read == RIFF_CHUNK_SIZE+8 && !memcmp(wavBuffer, "RIFF", 4) && !memcmp(wavBuffer+8, "WAVEfmt ", 8)) {
567 uint32_t size = *((uint32_t *)(wavBuffer+16));
568 result = (size < 256 ? f_read(&state.file, wavBuffer, size+8, &read) : FR_DENIED);
569 if (result == FR_OK && read == size+8) {
570 state.codec = ((uint16_t *)wavBuffer)[0];
571 state.freq = ((uint16_t *)wavBuffer)[2];
572 uint32_t *wavSamplesPtr = (uint32_t *)(wavBuffer + size);
573 uint32_t size = wavSamplesPtr[1];
574 if (state.freq != 0 && state.freq * (AUDIO_SAMPLE_RATE / state.freq) == AUDIO_SAMPLE_RATE) {
575 state.resampleRatio = (AUDIO_SAMPLE_RATE / state.freq);
576 state.readSize = (state.codec == CODEC_ID_PCM_S16LE ? 2*AUDIO_BUFFER_SIZE : AUDIO_BUFFER_SIZE) / state.resampleRatio;
578 else {
579 result = FR_DENIED;
581 while (result == FR_OK && memcmp(wavSamplesPtr, "data", 4) != 0) {
582 result = f_lseek(&state.file, f_tell(&state.file)+size);
583 if (result == FR_OK) {
584 result = f_read(&state.file, wavBuffer, 8, &read);
585 if (read != 8) result = FR_DENIED;
586 wavSamplesPtr = (uint32_t *)wavBuffer;
587 size = wavSamplesPtr[1];
590 state.size = size;
592 else {
593 result = FR_DENIED;
596 else {
597 result = FR_DENIED;
602 if (result == FR_OK) {
603 read = 0;
604 result = f_read(&state.file, wavBuffer, state.readSize, &read);
605 if (result == FR_OK) {
606 if (read > state.size) {
607 read = state.size;
609 state.size -= read;
611 if (read != state.readSize) {
612 f_close(&state.file);
613 fragment.clear();
616 audio_data_t * samples = buffer->data;
617 if (state.codec == CODEC_ID_PCM_S16LE) {
618 read /= 2;
619 for (uint32_t i=0; i<read; i++) {
620 for (uint8_t j=0; j<state.resampleRatio; j++) {
621 mixSample(samples++, ((int16_t *)wavBuffer)[i], fade+2-volume);
625 else if (state.codec == CODEC_ID_PCM_ALAW) {
626 for (uint32_t i=0; i<read; i++) {
627 for (uint8_t j=0; j<state.resampleRatio; j++) {
628 mixSample(samples++, alawTable[wavBuffer[i]], fade+2-volume);
632 else if (state.codec == CODEC_ID_PCM_MULAW) {
633 for (uint32_t i=0; i<read; i++) {
634 for (uint8_t j=0; j<state.resampleRatio; j++) {
635 mixSample(samples++, ulawTable[wavBuffer[i]], fade+2-volume);
640 return samples - buffer->data;
644 if (result != FR_OK) {
645 clear();
647 return 0;
649 #else
650 int WavContext::mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade)
652 return 0;
654 #endif
656 const unsigned int toneVolumes[] = { 10, 8, 6, 4, 2 };
657 inline float evalVolumeRatio(int freq, int volume)
659 float result = toneVolumes[2+volume];
660 if (freq < 330) {
661 result = (result * freq * freq) / (330 * 330);
663 return result;
666 int ToneContext::mixBuffer(AudioBuffer * buffer, int volume, unsigned int fade)
668 int duration = 0;
669 int result = 0;
671 int remainingDuration = fragment.tone.duration - state.duration;
672 if (remainingDuration > 0) {
673 int points;
674 float toneIdx = state.idx;
676 if (fragment.tone.reset) {
677 fragment.tone.reset = 0;
678 state.duration = 0;
679 state.pause = 0;
682 if (fragment.tone.freq != state.freq) {
683 state.freq = fragment.tone.freq;
684 state.step = limit<float>(1, float(fragment.tone.freq) * (float(DIM(sineValues))/float(AUDIO_SAMPLE_RATE)), 512);
685 state.volume = 1.0f / evalVolumeRatio(fragment.tone.freq, volume);
688 if (fragment.tone.freqIncr) {
689 int freqChange = AUDIO_BUFFER_DURATION * fragment.tone.freqIncr;
690 if (freqChange > 0) {
691 fragment.tone.freq += freqChange;
692 if (fragment.tone.freq > BEEP_MAX_FREQ) {
693 fragment.tone.freq = BEEP_MAX_FREQ;
696 else {
697 if (fragment.tone.freq > BEEP_MIN_FREQ - freqChange) {
698 fragment.tone.freq += freqChange;
700 else {
701 fragment.tone.freq = BEEP_MIN_FREQ;
706 if (remainingDuration > AUDIO_BUFFER_DURATION) {
707 duration = AUDIO_BUFFER_DURATION;
708 points = AUDIO_BUFFER_SIZE;
710 else {
711 duration = remainingDuration;
712 points = (duration * AUDIO_BUFFER_SIZE) / AUDIO_BUFFER_DURATION;
713 unsigned int end = toneIdx + (state.step * points);
714 if (end > DIM(sineValues))
715 end -= (end % DIM(sineValues));
716 else
717 end = DIM(sineValues);
718 points = (float(end) - toneIdx) / state.step;
721 for (int i=0; i<points; i++) {
722 int16_t sample = sineValues[int(toneIdx)] * state.volume;
723 mixSample(&buffer->data[i], sample, fade);
724 toneIdx += state.step;
725 if ((unsigned int)toneIdx >= DIM(sineValues))
726 toneIdx -= DIM(sineValues);
729 if (remainingDuration > AUDIO_BUFFER_DURATION) {
730 state.duration += AUDIO_BUFFER_DURATION;
731 state.idx = toneIdx;
732 return AUDIO_BUFFER_SIZE;
734 else {
735 state.duration = 32000; // once the tone is finished, it's not possible to update its frequency and duration
739 remainingDuration = fragment.tone.pause - state.pause;
740 if (remainingDuration > 0) {
741 result = AUDIO_BUFFER_SIZE;
742 state.pause += min<unsigned int>(AUDIO_BUFFER_DURATION-duration, fragment.tone.pause);
743 if (fragment.tone.pause > state.pause)
744 return result;
747 clear();
748 return result;
751 void AudioQueue::wakeup()
753 DEBUG_TIMER_START(debugTimerAudioConsume);
754 audioConsumeCurrentBuffer();
755 DEBUG_TIMER_STOP(debugTimerAudioConsume);
757 AudioBuffer * buffer;
758 while ((buffer = buffersFifo.getEmptyBuffer()) != nullptr) {
759 int result;
760 unsigned int fade = 0;
761 int size = 0;
763 // write silence in the buffer
764 for (uint32_t i=0; i<AUDIO_BUFFER_SIZE; i++) {
765 buffer->data[i] = AUDIO_DATA_SILENCE; /* silence */
768 // mix the priority context (only tones)
769 result = priorityContext.mixBuffer(buffer, g_eeGeneral.beepVolume, fade);
770 if (result > 0) {
771 size = result;
772 fade += 1;
775 // mix the normal context (tones and wavs)
776 if (normalContext.isEmpty() && !fragmentsFifo.empty()) {
777 RTOS_LOCK_MUTEX(audioMutex);
778 normalContext.setFragment(fragmentsFifo.get());
779 RTOS_UNLOCK_MUTEX(audioMutex);
781 result = normalContext.mixBuffer(buffer, g_eeGeneral.beepVolume, g_eeGeneral.wavVolume, fade);
782 if (result > 0) {
783 size = max(size, result);
784 fade += 1;
787 // mix the vario context
788 result = varioContext.mixBuffer(buffer, g_eeGeneral.varioVolume, fade);
789 if (result > 0) {
790 size = max(size, result);
791 fade += 1;
794 // mix the background context
795 if (isFunctionActive(FUNCTION_BACKGND_MUSIC) && !isFunctionActive(FUNCTION_BACKGND_MUSIC_PAUSE)) {
796 result = backgroundContext.mixBuffer(buffer, g_eeGeneral.backgroundVolume, fade);
797 if (result > 0) {
798 size = max(size, result);
802 // push the buffer if needed
803 if (size > 0) {
804 // TRACE("pushing buffer %p", buffer);
805 buffer->size = size;
807 #if defined(SOFTWARE_VOLUME)
808 if (currentSpeakerVolume > 0) {
809 for (uint32_t i=0; i<buffer->size; ++i) {
810 int32_t tmpSample = (int32_t) ((uint32_t) (buffer->data[i]) - AUDIO_DATA_SILENCE); // conversion from uint16_t
811 buffer->data[i] = (int16_t) (((tmpSample * currentSpeakerVolume) / VOLUME_LEVEL_MAX) + AUDIO_DATA_SILENCE);
813 buffersFifo.audioPushBuffer();
815 else {
816 break;
818 #else
819 buffersFifo.audioPushBuffer();
820 #endif
822 else {
823 // break the endless loop
824 break;
826 DEBUG_TIMER_START(debugTimerAudioConsume);
827 audioConsumeCurrentBuffer();
828 DEBUG_TIMER_STOP(debugTimerAudioConsume);
832 inline unsigned int getToneLength(uint16_t len)
834 unsigned int result = len; // default
835 if (g_eeGeneral.beepLength < 0) {
836 result /= (1-g_eeGeneral.beepLength);
838 else if (g_eeGeneral.beepLength > 0) {
839 result *= (1+g_eeGeneral.beepLength);
841 return result;
844 void AudioQueue::pause(uint16_t len)
846 playTone(0, 0, len);
849 bool AudioQueue::isPlaying(uint8_t id)
851 return normalContext.hasPromptId(id) ||
852 (isFunctionActive(FUNCTION_BACKGND_MUSIC) && backgroundContext.hasPromptId(id)) ||
853 fragmentsFifo.hasPromptId(id);
856 void AudioQueue::playTone(uint16_t freq, uint16_t len, uint16_t pause, uint8_t flags, int8_t freqIncr)
858 #if defined(SIMU) && !defined(SIMU_AUDIO)
859 return;
860 #endif
862 RTOS_LOCK_MUTEX(audioMutex);
864 freq = limit<uint16_t>(BEEP_MIN_FREQ, freq, BEEP_MAX_FREQ);
866 if (flags & PLAY_BACKGROUND) {
867 varioContext.setFragment(freq, len, pause, 0, 0, (flags & PLAY_NOW));
869 else {
870 // adjust frequency and length according to the user preferences
871 freq += g_eeGeneral.speakerPitch * 15;
872 len = getToneLength(len);
874 if (flags & PLAY_NOW) {
875 if (priorityContext.isFree()) {
876 priorityContext.clear();
877 priorityContext.setFragment(freq, len, pause, flags & 0x0f, freqIncr, false);
880 else {
881 fragmentsFifo.push(AudioFragment(freq, len, pause, flags & 0x0f, freqIncr, false));
885 RTOS_UNLOCK_MUTEX(audioMutex);
888 #if defined(SDCARD)
889 void AudioQueue::playFile(const char * filename, uint8_t flags, uint8_t id)
891 #if defined(SIMU)
892 TRACE("playFile(\"%s\", flags=%x, id=%d)", filename, flags, id);
893 if (strlen(filename) > AUDIO_FILENAME_MAXLEN) {
894 TRACE("file name too long! maximum length is %d characters", AUDIO_FILENAME_MAXLEN);
895 return;
897 #if !defined(SIMU_AUDIO)
898 return;
899 #endif
900 #endif
902 if (!sdMounted())
903 return;
905 if (g_eeGeneral.beepMode == e_mode_quiet)
906 return;
908 if (strlen(filename) > AUDIO_FILENAME_MAXLEN) {
909 POPUP_WARNING(STR_PATH_TOO_LONG);
910 return;
913 RTOS_LOCK_MUTEX(audioMutex);
915 if (flags & PLAY_BACKGROUND) {
916 backgroundContext.clear();
917 backgroundContext.setFragment(filename, 0, id);
919 else {
920 fragmentsFifo.push(AudioFragment(filename, flags & 0x0f, id));
923 RTOS_UNLOCK_MUTEX(audioMutex);
926 void AudioQueue::stopPlay(uint8_t id)
928 #if defined(SIMU)
929 TRACE("stopPlay(id=%d)", id);
930 #endif
932 #if defined(SIMU) && !defined(SIMU_AUDIO)
933 return;
934 #endif
936 RTOS_LOCK_MUTEX(audioMutex);
938 fragmentsFifo.removePromptById(id);
939 backgroundContext.stop(id);
941 RTOS_UNLOCK_MUTEX(audioMutex);
944 void AudioQueue::stopSD()
946 sdAvailableSystemAudioFiles.reset();
947 stopAll();
948 playTone(0, 0, 100, PLAY_NOW); // insert a 100ms pause
951 #endif
953 void AudioQueue::stopAll()
955 flush();
956 RTOS_LOCK_MUTEX(audioMutex);
957 priorityContext.clear();
958 normalContext.clear();
959 RTOS_UNLOCK_MUTEX(audioMutex);
962 void AudioQueue::flush()
964 RTOS_LOCK_MUTEX(audioMutex);
965 fragmentsFifo.clear();
966 varioContext.clear();
967 backgroundContext.clear();
968 RTOS_UNLOCK_MUTEX(audioMutex);
971 void audioPlay(unsigned int index, uint8_t id)
973 if (g_eeGeneral.beepMode >= -1) {
974 char filename[AUDIO_FILENAME_MAXLEN+1];
975 if (isAudioFileReferenced(index, filename)) {
976 audioQueue.playFile(filename, 0, id);
981 void audioKeyPress()
983 if (g_eeGeneral.beepMode == e_mode_all) {
984 audioQueue.playTone(BEEP_DEFAULT_FREQ, 40, 20, PLAY_NOW);
986 #if defined(HAPTIC)
987 if (g_eeGeneral.hapticMode == e_mode_all) {
988 haptic.play(5, 0, PLAY_NOW);
990 #endif
993 void audioKeyError()
995 if (g_eeGeneral.beepMode >= e_mode_nokeys) {
996 audioQueue.playTone(BEEP_DEFAULT_FREQ, 160, 20, PLAY_NOW);
999 #if defined(HAPTIC)
1000 if (g_eeGeneral.hapticMode >= e_mode_nokeys) {
1001 haptic.play(15, 3, PLAY_NOW);
1003 #endif
1006 void audioTrimPress(int value)
1008 if (g_eeGeneral.beepMode >= e_mode_nokeys) {
1009 value = limit(TRIM_MIN, value, TRIM_MAX) * 8 + 120*16;
1010 audioQueue.playTone(value, 40, 20, PLAY_NOW);
1014 void audioTimerCountdown(uint8_t timer, int value)
1016 if (g_model.timers[timer].countdownBeep == COUNTDOWN_VOICE) {
1017 if (value >= 0 && value <= TIMER_COUNTDOWN_START(timer)) {
1018 playNumber(value, 0, 0, 0);
1020 else if (value == 30 || value == 20) {
1021 playDuration(value, 0, 0);
1024 else if (g_model.timers[timer].countdownBeep == COUNTDOWN_BEEPS) {
1025 if (value == 0) {
1026 audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 300, 20, PLAY_NOW);
1028 else if (value > 0 && value <= TIMER_COUNTDOWN_START(timer)) {
1029 audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 100, 20, PLAY_NOW);
1031 else if (value == 30) {
1032 audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 120, 20, PLAY_REPEAT(2));
1034 else if (value == 20) {
1035 audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 120, 20, PLAY_REPEAT(1));
1037 else if (value == 10) {
1038 audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 120, 20, PLAY_NOW);
1041 #if defined(HAPTIC)
1042 else if (g_model.timers[timer].countdownBeep == COUNTDOWN_HAPTIC) {
1043 if (value == 0) {
1044 haptic.play(15, 3, PLAY_NOW);
1046 else if (value > 0 && value <= TIMER_COUNTDOWN_START(timer)) {
1047 haptic.play(10, 0, PLAY_NOW);
1049 else if (value == 30) {
1050 haptic.play(10, 3, PLAY_REPEAT(2) | PLAY_NOW);
1052 else if (value == 20) {
1053 haptic.play(10, 3, PLAY_REPEAT(1) | PLAY_NOW);
1055 else if (value == 10) {
1056 haptic.play(10, 3, PLAY_NOW);
1059 #endif
1062 void audioEvent(unsigned int index)
1064 if (index == AU_NONE)
1065 return;
1067 #if defined(HAPTIC)
1068 haptic.event(index); // do this before audio to help sync timings
1069 #endif
1071 if (index <= AU_ERROR) {
1072 if (g_eeGeneral.alarmsFlash) {
1073 flashCounter = FLASH_DURATION;
1077 if (g_eeGeneral.beepMode >= e_mode_nokeys || (g_eeGeneral.beepMode >= e_mode_alarms && index <= AU_ERROR)) {
1078 #if defined(SDCARD)
1079 char filename[AUDIO_FILENAME_MAXLEN + 1];
1080 if (index < AU_SPECIAL_SOUND_FIRST && isAudioFileReferenced(index, filename)) {
1081 audioQueue.stopPlay(ID_PLAY_PROMPT_BASE + index);
1082 audioQueue.playFile(filename, 0, ID_PLAY_PROMPT_BASE + index);
1083 return;
1085 #endif
1086 switch (index) {
1087 case AU_INACTIVITY:
1088 audioQueue.playTone(2250, 80, 20, PLAY_REPEAT(2));
1089 break;
1090 case AU_TX_BATTERY_LOW:
1091 #if defined(PCBSKY9X)
1092 case AU_TX_MAH_HIGH:
1093 case AU_TX_TEMP_HIGH:
1094 #endif
1095 audioQueue.playTone(1950, 160, 20, PLAY_REPEAT(2), 1);
1096 audioQueue.playTone(2550, 160, 20, PLAY_REPEAT(2), -1);
1097 break;
1098 case AU_THROTTLE_ALERT:
1099 case AU_SWITCH_ALERT:
1100 case AU_ERROR:
1101 audioQueue.playTone(BEEP_DEFAULT_FREQ, 200, 20, PLAY_NOW);
1102 break;
1103 case AU_TRIM_MIDDLE:
1104 audioQueue.playTone(120*16, 80, 20, PLAY_NOW);
1105 break;
1106 case AU_TRIM_MIN:
1107 audioQueue.playTone(TRIM_MIN*8 + 120*16, 80, 20, PLAY_NOW);
1108 break;
1109 case AU_TRIM_MAX:
1110 audioQueue.playTone(TRIM_MAX*8 + 120*16, 80, 20, PLAY_NOW);
1111 break;
1112 case AU_WARNING1:
1113 audioQueue.playTone(BEEP_DEFAULT_FREQ, 80, 20, PLAY_NOW);
1114 break;
1115 case AU_WARNING2:
1116 audioQueue.playTone(BEEP_DEFAULT_FREQ, 160, 20, PLAY_NOW);
1117 break;
1118 case AU_WARNING3:
1119 audioQueue.playTone(BEEP_DEFAULT_FREQ, 200, 20, PLAY_NOW);
1120 break;
1121 // TODO remove all these ones
1122 case AU_STICK1_MIDDLE:
1123 case AU_STICK2_MIDDLE:
1124 case AU_STICK3_MIDDLE:
1125 case AU_STICK4_MIDDLE:
1126 case AU_POT1_MIDDLE:
1127 case AU_POT2_MIDDLE:
1128 #if defined(PCBX9E)
1129 case AU_POT3_MIDDLE:
1130 case AU_POT4_MIDDLE:
1131 #endif
1132 #if defined(PCBTARANIS) || defined(PCBHORUS)
1133 case AU_SLIDER1_MIDDLE:
1134 case AU_SLIDER2_MIDDLE:
1135 #if defined(PCBX9E)
1136 case AU_SLIDER3_MIDDLE:
1137 case AU_SLIDER4_MIDDLE:
1138 #endif
1139 #else
1140 case AU_POT3_MIDDLE:
1141 #endif
1142 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 80, 20, PLAY_NOW);
1143 break;
1144 case AU_MIX_WARNING_1:
1145 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1440, 48, 32);
1146 break;
1147 case AU_MIX_WARNING_2:
1148 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1560, 48, 32, PLAY_REPEAT(1));
1149 break;
1150 case AU_MIX_WARNING_3:
1151 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1680, 48, 32, PLAY_REPEAT(2));
1152 break;
1153 case AU_TIMER1_ELAPSED:
1154 case AU_TIMER2_ELAPSED:
1155 case AU_TIMER3_ELAPSED:
1156 audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 300, 20, PLAY_NOW);
1157 break;
1158 case AU_RSSI_ORANGE:
1159 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 800, 20, PLAY_NOW);
1160 break;
1161 case AU_RSSI_RED:
1162 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1800, 800, 20, PLAY_REPEAT(1) | PLAY_NOW);
1163 break;
1164 case AU_RAS_RED:
1165 audioQueue.playTone(450, 160, 40, PLAY_REPEAT(2), 1);
1166 break;
1167 case AU_SPECIAL_SOUND_BEEP1:
1168 audioQueue.playTone(BEEP_DEFAULT_FREQ, 60, 20);
1169 break;
1170 case AU_SPECIAL_SOUND_BEEP2:
1171 audioQueue.playTone(BEEP_DEFAULT_FREQ, 120, 20);
1172 break;
1173 case AU_SPECIAL_SOUND_BEEP3:
1174 audioQueue.playTone(BEEP_DEFAULT_FREQ, 200, 20);
1175 break;
1176 case AU_SPECIAL_SOUND_WARN1:
1177 audioQueue.playTone(BEEP_DEFAULT_FREQ + 600, 120, 40, PLAY_REPEAT(2));
1178 break;
1179 case AU_SPECIAL_SOUND_WARN2:
1180 audioQueue.playTone(BEEP_DEFAULT_FREQ + 900, 120, 40, PLAY_REPEAT(2));
1181 break;
1182 case AU_SPECIAL_SOUND_CHEEP:
1183 audioQueue.playTone(BEEP_DEFAULT_FREQ + 900, 80, 20, PLAY_REPEAT(2), 2);
1184 break;
1185 case AU_SPECIAL_SOUND_RING:
1186 audioQueue.playTone(BEEP_DEFAULT_FREQ + 750, 40, 20, PLAY_REPEAT(10));
1187 audioQueue.playTone(BEEP_DEFAULT_FREQ + 750, 40, 80, PLAY_REPEAT(1));
1188 audioQueue.playTone(BEEP_DEFAULT_FREQ + 750, 40, 20, PLAY_REPEAT(10));
1189 break;
1190 case AU_SPECIAL_SOUND_SCIFI:
1191 audioQueue.playTone(2550, 80, 20, PLAY_REPEAT(2), -1);
1192 audioQueue.playTone(1950, 80, 20, PLAY_REPEAT(2), 1);
1193 audioQueue.playTone(2250, 80, 20, 0);
1194 break;
1195 case AU_SPECIAL_SOUND_ROBOT:
1196 audioQueue.playTone(2250, 40, 20, PLAY_REPEAT(1));
1197 audioQueue.playTone(1650, 120, 20, PLAY_REPEAT(1));
1198 audioQueue.playTone(2550, 120, 20, PLAY_REPEAT(1));
1199 break;
1200 case AU_SPECIAL_SOUND_CHIRP:
1201 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1200, 40, 20, PLAY_REPEAT(2));
1202 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1620, 40, 20, PLAY_REPEAT(3));
1203 break;
1204 case AU_SPECIAL_SOUND_TADA:
1205 audioQueue.playTone(1650, 80, 40);
1206 audioQueue.playTone(2850, 80, 40);
1207 audioQueue.playTone(3450, 64, 36, PLAY_REPEAT(2));
1208 break;
1209 case AU_SPECIAL_SOUND_CRICKET:
1210 audioQueue.playTone(2550, 40, 80, PLAY_REPEAT(3));
1211 audioQueue.playTone(2550, 40, 160, PLAY_REPEAT(1));
1212 audioQueue.playTone(2550, 40, 80, PLAY_REPEAT(3));
1213 break;
1214 case AU_SPECIAL_SOUND_SIREN:
1215 audioQueue.playTone(450, 160, 40, PLAY_REPEAT(2), 2);
1216 break;
1217 case AU_SPECIAL_SOUND_ALARMC:
1218 audioQueue.playTone(1650, 32, 68, PLAY_REPEAT(2));
1219 audioQueue.playTone(2250, 64, 156, PLAY_REPEAT(1));
1220 audioQueue.playTone(1650, 64, 76, PLAY_REPEAT(2));
1221 audioQueue.playTone(2250, 32, 168, PLAY_REPEAT(1));
1222 break;
1223 case AU_SPECIAL_SOUND_RATATA:
1224 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 40, 80, PLAY_REPEAT(10));
1225 break;
1226 case AU_SPECIAL_SOUND_TICK:
1227 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 40, 400, PLAY_REPEAT(2));
1228 break;
1229 default:
1230 break;
1235 #if defined(SDCARD)
1236 void pushUnit(uint8_t unit, uint8_t idx, uint8_t id)
1238 if (unit < DIM(unitsFilenames)) {
1239 char path[AUDIO_FILENAME_MAXLEN+1];
1240 char * tmp = strAppendSystemAudioPath(path);
1241 tmp = strAppendStringWithIndex(tmp, unitsFilenames[unit], idx);
1242 strcpy(tmp, SOUNDS_EXT);
1243 audioQueue.playFile(path, 0, id);
1245 else {
1246 TRACE("pushUnit: out of bounds unit : %d", unit); // We should never get here, but given the nature of TTS files, this prevent segfault in case of bug there.
1249 #endif
1251 void pushPrompt(uint16_t prompt, uint8_t id)
1253 #if defined(SDCARD)
1254 char filename[AUDIO_FILENAME_MAXLEN+1];
1255 char * str = strAppendSystemAudioPath(filename);
1256 strcpy(str, "0000" SOUNDS_EXT);
1257 for (int8_t i=3; i>=0; i--) {
1258 str[i] = '0' + (prompt%10);
1259 prompt /= 10;
1261 audioQueue.playFile(filename, 0, id);
1262 #endif