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.
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,
135 const char * const unitsFilenames
[] = {
176 const char * const audioFilenames
[] = {
195 #if defined(PCBSKY9X)
210 #if defined(PCBTARANIS) || defined(PCBHORUS)
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];
269 sdAvailableSystemAudioFiles
.reset();
271 char * filename
= strAppendSystemAudioPath(path
);
272 *(filename
-1) = '\0';
274 FRESULT res
= f_opendir(&dir
, path
); /* Open the directory */
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
);
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
));
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
);
324 *str
++ = 'A' + swinfo
.quot
;
325 const char * positions
[] = { "-up", "-mid", "-down" };
326 strcpy(str
, positions
[swinfo
.rem
]);
329 div_t swinfo
= div(int(index
- SWSRC_FIRST_MULTIPOS_SWITCH
), XPOTS_MULTIPOS_COUNT
);
331 *str
++ = '1' + swinfo
.quot
;
332 *str
++ = '1' + swinfo
.rem
;
336 int len
= STR_VSWITCHES
[0];
337 strncpy(str
, &STR_VSWITCHES
[1+(len
*index
)], len
);
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)
351 div_t qr
= div(index
+1, 10);
352 *str
++ = '0' + qr
.quot
;
353 *str
++ = '0' + qr
.rem
;
356 *str
++ = '1' + index
;
359 int len
= STR_VSWITCHES
[0];
360 strncpy(str
, &STR_VSWITCHES
[1+len
*(index
+SWSRC_FIRST_LOGICAL_SWITCH
)], len
);
364 strcpy(str
, suffixes
[event
]);
365 strcat(str
, SOUNDS_EXT
);
368 void referenceModelAudioFiles()
370 char path
[AUDIO_FILENAME_MAXLEN
+1];
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 */
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
);
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
));
401 TRACE("\tfound: %s", filename
);
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
);
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
));
426 TRACE("\tfound: %s", filename
);
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
);
450 else if (category
== PHASE_AUDIO_CATEGORY
) {
451 if (sdAvailableFlightmodeAudioFiles
.getBit(INDEX_PHASE_AUDIO_FILE(index
, event
))) {
452 getFlightmodeAudioFile(filename
, index
, event
);
456 else if (category
== SWITCH_AUDIO_CATEGORY
) {
457 if (sdAvailableSwitchAudioFiles
.getBit(index
)) {
458 getSwitchAudioFile(filename
, SWSRC_FIRST_SWITCH
+index
);
462 else if (category
== LOGICAL_SWITCH_AUDIO_CATEGORY
) {
463 if (sdAvailableLogicalSwitchAudioFiles
.getBit(INDEX_LOGICAL_SWITCH_AUDIO_FILE(index
, event
))) {
464 getLogicalSwitchAudioFile(filename
, index
, event
);
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
);
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()
514 #define CODEC_ID_PCM_S16LE 1
515 #define CODEC_ID_PCM_ALAW 6
516 #define CODEC_ID_PCM_MULAW 7
519 void audioTask(void * pdata
)
521 while (!audioQueue
.started()) {
525 setSampleRate(AUDIO_SAMPLE_RATE
);
528 // The audio amp needs ~2s to start
529 RTOS_WAIT_MS(1000); // 1s
532 if (!globalData
.unexpectedShutdown
) {
537 DEBUG_TIMER_SAMPLE(debugTimerAudioIterval
);
538 DEBUG_TIMER_START(debugTimerAudioDuration
);
540 DEBUG_TIMER_STOP(debugTimerAudioDuration
);
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
);
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
;
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
;
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];
602 if (result
== FR_OK
) {
604 result
= f_read(&state
.file
, wavBuffer
, state
.readSize
, &read
);
605 if (result
== FR_OK
) {
606 if (read
> state
.size
) {
611 if (read
!= state
.readSize
) {
612 f_close(&state
.file
);
616 audio_data_t
* samples
= buffer
->data
;
617 if (state
.codec
== CODEC_ID_PCM_S16LE
) {
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
) {
650 int WavContext::mixBuffer(AudioBuffer
*buffer
, int volume
, unsigned int fade
)
656 const unsigned int toneVolumes
[] = { 10, 8, 6, 4, 2 };
657 inline float evalVolumeRatio(int freq
, int volume
)
659 float result
= toneVolumes
[2+volume
];
661 result
= (result
* freq
* freq
) / (330 * 330);
666 int ToneContext::mixBuffer(AudioBuffer
* buffer
, int volume
, unsigned int fade
)
671 int remainingDuration
= fragment
.tone
.duration
- state
.duration
;
672 if (remainingDuration
> 0) {
674 float toneIdx
= state
.idx
;
676 if (fragment
.tone
.reset
) {
677 fragment
.tone
.reset
= 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
;
697 if (fragment
.tone
.freq
> BEEP_MIN_FREQ
- freqChange
) {
698 fragment
.tone
.freq
+= freqChange
;
701 fragment
.tone
.freq
= BEEP_MIN_FREQ
;
706 if (remainingDuration
> AUDIO_BUFFER_DURATION
) {
707 duration
= AUDIO_BUFFER_DURATION
;
708 points
= AUDIO_BUFFER_SIZE
;
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
));
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
;
732 return AUDIO_BUFFER_SIZE
;
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
)
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) {
760 unsigned int fade
= 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
);
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
);
783 size
= max(size
, result
);
787 // mix the vario context
788 result
= varioContext
.mixBuffer(buffer
, g_eeGeneral
.varioVolume
, fade
);
790 size
= max(size
, result
);
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
);
798 size
= max(size
, result
);
802 // push the buffer if needed
804 // TRACE("pushing buffer %p", buffer);
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();
819 buffersFifo
.audioPushBuffer();
823 // break the endless loop
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
);
844 void AudioQueue::pause(uint16_t 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)
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
));
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);
881 fragmentsFifo
.push(AudioFragment(freq
, len
, pause
, flags
& 0x0f, freqIncr
, false));
885 RTOS_UNLOCK_MUTEX(audioMutex
);
889 void AudioQueue::playFile(const char * filename
, uint8_t flags
, uint8_t id
)
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
);
897 #if !defined(SIMU_AUDIO)
905 if (g_eeGeneral
.beepMode
== e_mode_quiet
)
908 if (strlen(filename
) > AUDIO_FILENAME_MAXLEN
) {
909 POPUP_WARNING(STR_PATH_TOO_LONG
);
913 RTOS_LOCK_MUTEX(audioMutex
);
915 if (flags
& PLAY_BACKGROUND
) {
916 backgroundContext
.clear();
917 backgroundContext
.setFragment(filename
, 0, id
);
920 fragmentsFifo
.push(AudioFragment(filename
, flags
& 0x0f, id
));
923 RTOS_UNLOCK_MUTEX(audioMutex
);
926 void AudioQueue::stopPlay(uint8_t id
)
929 TRACE("stopPlay(id=%d)", id
);
932 #if defined(SIMU) && !defined(SIMU_AUDIO)
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();
948 playTone(0, 0, 100, PLAY_NOW
); // insert a 100ms pause
953 void AudioQueue::stopAll()
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
);
983 if (g_eeGeneral
.beepMode
== e_mode_all
) {
984 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 40, 20, PLAY_NOW
);
987 if (g_eeGeneral
.hapticMode
== e_mode_all
) {
988 haptic
.play(5, 0, PLAY_NOW
);
995 if (g_eeGeneral
.beepMode
>= e_mode_nokeys
) {
996 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 160, 20, PLAY_NOW
);
1000 if (g_eeGeneral
.hapticMode
>= e_mode_nokeys
) {
1001 haptic
.play(15, 3, PLAY_NOW
);
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
) {
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
);
1042 else if (g_model
.timers
[timer
].countdownBeep
== COUNTDOWN_HAPTIC
) {
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
);
1062 void audioEvent(unsigned int index
)
1064 if (index
== AU_NONE
)
1068 haptic
.event(index
); // do this before audio to help sync timings
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
)) {
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
);
1088 audioQueue
.playTone(2250, 80, 20, PLAY_REPEAT(2));
1090 case AU_TX_BATTERY_LOW
:
1091 #if defined(PCBSKY9X)
1092 case AU_TX_MAH_HIGH
:
1093 case AU_TX_TEMP_HIGH
:
1095 audioQueue
.playTone(1950, 160, 20, PLAY_REPEAT(2), 1);
1096 audioQueue
.playTone(2550, 160, 20, PLAY_REPEAT(2), -1);
1098 case AU_THROTTLE_ALERT
:
1099 case AU_SWITCH_ALERT
:
1101 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 200, 20, PLAY_NOW
);
1103 case AU_TRIM_MIDDLE
:
1104 audioQueue
.playTone(120*16, 80, 20, PLAY_NOW
);
1107 audioQueue
.playTone(TRIM_MIN
*8 + 120*16, 80, 20, PLAY_NOW
);
1110 audioQueue
.playTone(TRIM_MAX
*8 + 120*16, 80, 20, PLAY_NOW
);
1113 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 80, 20, PLAY_NOW
);
1116 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 160, 20, PLAY_NOW
);
1119 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 200, 20, PLAY_NOW
);
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
:
1129 case AU_POT3_MIDDLE
:
1130 case AU_POT4_MIDDLE
:
1132 #if defined(PCBTARANIS) || defined(PCBHORUS)
1133 case AU_SLIDER1_MIDDLE
:
1134 case AU_SLIDER2_MIDDLE
:
1136 case AU_SLIDER3_MIDDLE
:
1137 case AU_SLIDER4_MIDDLE
:
1140 case AU_POT3_MIDDLE
:
1142 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 80, 20, PLAY_NOW
);
1144 case AU_MIX_WARNING_1
:
1145 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1440, 48, 32);
1147 case AU_MIX_WARNING_2
:
1148 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1560, 48, 32, PLAY_REPEAT(1));
1150 case AU_MIX_WARNING_3
:
1151 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1680, 48, 32, PLAY_REPEAT(2));
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
);
1158 case AU_RSSI_ORANGE
:
1159 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 800, 20, PLAY_NOW
);
1162 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1800, 800, 20, PLAY_REPEAT(1) | PLAY_NOW
);
1165 audioQueue
.playTone(450, 160, 40, PLAY_REPEAT(2), 1);
1167 case AU_SPECIAL_SOUND_BEEP1
:
1168 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 60, 20);
1170 case AU_SPECIAL_SOUND_BEEP2
:
1171 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 120, 20);
1173 case AU_SPECIAL_SOUND_BEEP3
:
1174 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 200, 20);
1176 case AU_SPECIAL_SOUND_WARN1
:
1177 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 600, 120, 40, PLAY_REPEAT(2));
1179 case AU_SPECIAL_SOUND_WARN2
:
1180 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 900, 120, 40, PLAY_REPEAT(2));
1182 case AU_SPECIAL_SOUND_CHEEP
:
1183 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 900, 80, 20, PLAY_REPEAT(2), 2);
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));
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);
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));
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));
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));
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));
1214 case AU_SPECIAL_SOUND_SIREN
:
1215 audioQueue
.playTone(450, 160, 40, PLAY_REPEAT(2), 2);
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));
1223 case AU_SPECIAL_SOUND_RATATA
:
1224 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 40, 80, PLAY_REPEAT(10));
1226 case AU_SPECIAL_SOUND_TICK
:
1227 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 40, 400, PLAY_REPEAT(2));
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
);
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.
1251 void pushPrompt(uint16_t prompt
, uint8_t id
)
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);
1261 audioQueue
.playFile(filename
, 0, id
);