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 OS_MutexID 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
[] = {
165 const char * const audioFilenames
[] = {
184 #if defined(PCBSKY9X)
199 #if defined(PCBTARANIS) || defined(PCBHORUS)
225 BitField
<(AU_SPECIAL_SOUND_FIRST
)> sdAvailableSystemAudioFiles
;
226 BitField
<(MAX_FLIGHT_MODES
* 2/*on, off*/)> sdAvailablePhaseAudioFiles
;
227 BitField
<(SWSRC_LAST_SWITCH
+NUM_XPOTS
*XPOTS_MULTIPOS_COUNT
)> sdAvailableSwitchAudioFiles
;
228 BitField
<(MAX_LOGICAL_SWITCHES
* 2/*on, off*/)> sdAvailableLogicalSwitchAudioFiles
;
230 char * getAudioPath(char * path
)
232 strcpy(path
, SOUNDS_PATH
"/");
233 strncpy(path
+SOUNDS_PATH_LNG_OFS
, currentLanguagePack
->id
, 2);
234 return path
+ sizeof(SOUNDS_PATH
);
237 char * strAppendSystemAudioPath(char * path
)
239 char * str
= getAudioPath(path
);
240 strcpy(str
, SYSTEM_SUBDIR
"/");
241 return str
+ sizeof(SYSTEM_SUBDIR
);
244 void getSystemAudioFile(char * filename
, int index
)
246 char * str
= strAppendSystemAudioPath(filename
);
247 strcpy(str
, audioFilenames
[index
]);
248 strcat(str
, SOUNDS_EXT
);
251 void referenceSystemAudioFiles()
253 static_assert(sizeof(audioFilenames
)==AU_SPECIAL_SOUND_FIRST
*sizeof(char *), "Invalid audioFilenames size");
254 char path
[AUDIO_FILENAME_MAXLEN
+1];
258 sdAvailableSystemAudioFiles
.reset();
260 char * filename
= strAppendSystemAudioPath(path
);
261 *(filename
-1) = '\0';
263 FRESULT res
= f_opendir(&dir
, path
); /* Open the directory */
266 res
= f_readdir(&dir
, &fno
); /* Read a directory item */
267 if (res
!= FR_OK
|| fno
.fname
[0] == 0) break; /* Break on error or end of dir */
268 uint8_t len
= strlen(fno
.fname
);
270 // Eliminates directories / non wav files
271 if (len
< 5 || strcasecmp(fno
.fname
+len
-4, SOUNDS_EXT
) || (fno
.fattrib
& AM_DIR
)) continue;
273 for (int i
=0; i
<AU_SPECIAL_SOUND_FIRST
; i
++) {
274 getSystemAudioFile(path
, i
);
275 if (!strcasecmp(filename
, fno
.fname
)) {
276 sdAvailableSystemAudioFiles
.setBit(i
);
285 const char * const suffixes
[] = { "-off", "-on" };
287 char * getModelAudioPath(char * path
)
289 strcpy(path
, SOUNDS_PATH
"/");
290 strncpy(path
+SOUNDS_PATH_LNG_OFS
, currentLanguagePack
->id
, 2);
291 char * result
= strcat_currentmodelname(path
+sizeof(SOUNDS_PATH
));
297 void getPhaseAudioFile(char * filename
, int index
, unsigned int event
)
299 char * str
= getModelAudioPath(filename
);
300 char * tmp
= strcat_phasename(str
, index
);
301 strcpy(tmp
, suffixes
[event
]);
302 strcat(tmp
, SOUNDS_EXT
);
305 void getSwitchAudioFile(char * filename
, swsrc_t index
)
307 char * str
= getModelAudioPath(filename
);
309 #if defined(PCBTARANIS) || defined(PCBHORUS)
310 if (index
<= SWSRC_LAST_SWITCH
) {
311 div_t swinfo
= switchInfo(index
);
313 *str
++ = 'A' + swinfo
.quot
;
314 const char * positions
[] = { "-up", "-mid", "-down" };
315 strcpy(str
, positions
[swinfo
.rem
]);
318 div_t swinfo
= div(int(index
- SWSRC_FIRST_MULTIPOS_SWITCH
), XPOTS_MULTIPOS_COUNT
);
320 *str
++ = '1' + swinfo
.quot
;
321 *str
++ = '1' + swinfo
.rem
;
325 int len
= STR_VSWITCHES
[0];
326 strncpy(str
, &STR_VSWITCHES
[1+(len
*index
)], len
);
330 strcat(str
, SOUNDS_EXT
);
333 void getLogicalSwitchAudioFile(char * filename
, int index
, unsigned int event
)
335 char * str
= getModelAudioPath(filename
);
337 #if defined(PCBTARANIS) || defined(PCBHORUS)
340 div_t qr
= div(index
+1, 10);
341 *str
++ = '0' + qr
.quot
;
342 *str
++ = '0' + qr
.rem
;
345 *str
++ = '1' + index
;
348 int len
= STR_VSWITCHES
[0];
349 strncpy(str
, &STR_VSWITCHES
[1+len
*(index
+SWSRC_FIRST_LOGICAL_SWITCH
)], len
);
353 strcpy(str
, suffixes
[event
]);
354 strcat(str
, SOUNDS_EXT
);
357 void referenceModelAudioFiles()
359 char path
[AUDIO_FILENAME_MAXLEN
+1];
363 sdAvailablePhaseAudioFiles
.reset();
364 sdAvailableSwitchAudioFiles
.reset();
365 sdAvailableLogicalSwitchAudioFiles
.reset();
367 char * filename
= getModelAudioPath(path
);
368 *(filename
-1) = '\0';
370 FRESULT res
= f_opendir(&dir
, path
); /* Open the directory */
373 res
= f_readdir(&dir
, &fno
); /* Read a directory item */
374 if (res
!= FR_OK
|| fno
.fname
[0] == 0) break; /* Break on error or end of dir */
375 uint8_t len
= strlen(fno
.fname
);
378 // Eliminates directories / non wav files
379 if (len
< 5 || strcasecmp(fno
.fname
+len
-4, SOUNDS_EXT
) || (fno
.fattrib
& AM_DIR
)) continue;
380 TRACE("referenceModelAudioFiles(): using file: %s", fno
.fname
);
382 // Phases Audio Files <phasename>-[on|off].wav
383 for (int i
=0; i
<MAX_FLIGHT_MODES
&& !found
; i
++) {
384 for (int event
=0; event
<2; event
++) {
385 getPhaseAudioFile(path
, i
, event
);
386 // TRACE("referenceModelAudioFiles(): searching for %s in %s", filename, fno.fname);
387 if (!strcasecmp(filename
, fno
.fname
)) {
388 sdAvailablePhaseAudioFiles
.setBit(INDEX_PHASE_AUDIO_FILE(i
, event
));
390 TRACE("\tfound: %s", filename
);
396 // Switches Audio Files <switchname>-[up|mid|down].wav
397 for (int i
=SWSRC_FIRST_SWITCH
; i
<=SWSRC_LAST_SWITCH
+NUM_XPOTS
*XPOTS_MULTIPOS_COUNT
&& !found
; i
++) {
398 getSwitchAudioFile(path
, i
);
399 // TRACE("referenceModelAudioFiles(): searching for %s in %s (%d)", path, fno.fname, i);
400 if (!strcasecmp(filename
, fno
.fname
)) {
401 sdAvailableSwitchAudioFiles
.setBit(i
-SWSRC_FIRST_SWITCH
);
403 TRACE("\tfound: %s", filename
);
407 // Logical Switches Audio Files <switchname>-[on|off].wav
408 for (int i
=0; i
<MAX_LOGICAL_SWITCHES
&& !found
; i
++) {
409 for (int event
=0; event
<2; event
++) {
410 getLogicalSwitchAudioFile(path
, i
, event
);
411 // TRACE("referenceModelAudioFiles(): searching for %s in %s", filename, fno.fname);
412 if (!strcasecmp(filename
, fno
.fname
)) {
413 sdAvailableLogicalSwitchAudioFiles
.setBit(INDEX_LOGICAL_SWITCH_AUDIO_FILE(i
, event
));
415 TRACE("\tfound: %s", filename
);
425 bool isAudioFileReferenced(uint32_t i
, char * filename
)
427 uint8_t category
= (i
>> 24);
428 uint8_t index
= (i
>> 16) & 0xFF;
429 event_t event
= i
& 0xFF;
431 // TRACE("isAudioFileReferenced(%08x)", i);
433 if (category
== SYSTEM_AUDIO_CATEGORY
) {
434 if (sdAvailableSystemAudioFiles
.getBit(event
)) {
435 getSystemAudioFile(filename
, event
);
439 else if (category
== PHASE_AUDIO_CATEGORY
) {
440 if (sdAvailablePhaseAudioFiles
.getBit(INDEX_PHASE_AUDIO_FILE(index
, event
))) {
441 getPhaseAudioFile(filename
, index
, event
);
445 else if (category
== SWITCH_AUDIO_CATEGORY
) {
446 if (sdAvailableSwitchAudioFiles
.getBit(index
)) {
447 getSwitchAudioFile(filename
, SWSRC_FIRST_SWITCH
+index
);
451 else if (category
== LOGICAL_SWITCH_AUDIO_CATEGORY
) {
452 if (sdAvailableLogicalSwitchAudioFiles
.getBit(INDEX_LOGICAL_SWITCH_AUDIO_FILE(index
, event
))) {
453 getLogicalSwitchAudioFile(filename
, index
, event
);
461 tmr10ms_t timeAutomaticPromptsSilence
= 0;
463 void playModelEvent(uint8_t category
, uint8_t index
, event_t event
)
465 char filename
[AUDIO_FILENAME_MAXLEN
+1];
466 // TRACE("playModelEvent(): cat: %u, idx: %u, evt:%u", (uint32_t)category, (uint32_t)index, (uint32_t)event);
467 if (IS_SILENCE_PERIOD_ELAPSED() && isAudioFileReferenced((category
<< 24) + (index
<< 16) + event
, filename
)) {
468 audioQueue
.playFile(filename
);
474 char filename
[AUDIO_FILENAME_MAXLEN
+1];
475 char * str
= getModelAudioPath(filename
);
476 strcpy(str
, "name.wav");
477 audioQueue
.playFile(filename
);
480 #else // defined(SDCARD)
482 #define isAudioFileReferenced(i, f) false
484 #endif // defined(SDCARD)
486 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 };
487 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 };
489 AudioQueue audioQueue __DMA
; // to place it in the RAM section on Horus, to have file buffers in RAM for DMA access
490 AudioBuffer audioBuffers
[AUDIO_BUFFER_COUNT
] __DMA
;
492 AudioQueue::AudioQueue()
503 #define CODEC_ID_PCM_S16LE 1
504 #define CODEC_ID_PCM_ALAW 6
505 #define CODEC_ID_PCM_MULAW 7
508 void audioTask(void * pdata
)
510 while (!audioQueue
.started()) {
514 setSampleRate(AUDIO_SAMPLE_RATE
);
517 // The audio amp needs ~2s to start
518 CoTickDelay(500); // 1s
521 if (!unexpectedShutdown
) {
526 DEBUG_TIMER_SAMPLE(debugTimerAudioIterval
);
527 DEBUG_TIMER_START(debugTimerAudioDuration
);
529 DEBUG_TIMER_STOP(debugTimerAudioDuration
);
530 CoTickDelay(2/*4ms*/);
535 inline void mixSample(audio_data_t
* result
, int sample
, unsigned int fade
)
537 *result
= limit(AUDIO_DATA_MIN
, *result
+ ((sample
>> fade
) >> (16-AUDIO_BITS_PER_SAMPLE
)), AUDIO_DATA_MAX
);
542 #define RIFF_CHUNK_SIZE 12
543 uint8_t wavBuffer
[AUDIO_BUFFER_SIZE
*2] __DMA
;
545 int WavContext::mixBuffer(AudioBuffer
*buffer
, int volume
, unsigned int fade
)
547 FRESULT result
= FR_OK
;
550 if (fragment
.file
[1]) {
551 result
= f_open(&state
.file
, fragment
.file
, FA_OPEN_EXISTING
| FA_READ
);
552 fragment
.file
[1] = 0;
553 if (result
== FR_OK
) {
554 result
= f_read(&state
.file
, wavBuffer
, RIFF_CHUNK_SIZE
+8, &read
);
555 if (result
== FR_OK
&& read
== RIFF_CHUNK_SIZE
+8 && !memcmp(wavBuffer
, "RIFF", 4) && !memcmp(wavBuffer
+8, "WAVEfmt ", 8)) {
556 uint32_t size
= *((uint32_t *)(wavBuffer
+16));
557 result
= (size
< 256 ? f_read(&state
.file
, wavBuffer
, size
+8, &read
) : FR_DENIED
);
558 if (result
== FR_OK
&& read
== size
+8) {
559 state
.codec
= ((uint16_t *)wavBuffer
)[0];
560 state
.freq
= ((uint16_t *)wavBuffer
)[2];
561 uint32_t *wavSamplesPtr
= (uint32_t *)(wavBuffer
+ size
);
562 uint32_t size
= wavSamplesPtr
[1];
563 if (state
.freq
!= 0 && state
.freq
* (AUDIO_SAMPLE_RATE
/ state
.freq
) == AUDIO_SAMPLE_RATE
) {
564 state
.resampleRatio
= (AUDIO_SAMPLE_RATE
/ state
.freq
);
565 state
.readSize
= (state
.codec
== CODEC_ID_PCM_S16LE
? 2*AUDIO_BUFFER_SIZE
: AUDIO_BUFFER_SIZE
) / state
.resampleRatio
;
570 while (result
== FR_OK
&& memcmp(wavSamplesPtr
, "data", 4) != 0) {
571 result
= f_lseek(&state
.file
, f_tell(&state
.file
)+size
);
572 if (result
== FR_OK
) {
573 result
= f_read(&state
.file
, wavBuffer
, 8, &read
);
574 if (read
!= 8) result
= FR_DENIED
;
575 wavSamplesPtr
= (uint32_t *)wavBuffer
;
576 size
= wavSamplesPtr
[1];
591 if (result
== FR_OK
) {
593 result
= f_read(&state
.file
, wavBuffer
, state
.readSize
, &read
);
594 if (result
== FR_OK
) {
595 if (read
> state
.size
) {
600 if (read
!= state
.readSize
) {
601 f_close(&state
.file
);
605 audio_data_t
* samples
= buffer
->data
;
606 if (state
.codec
== CODEC_ID_PCM_S16LE
) {
608 for (uint32_t i
=0; i
<read
; i
++) {
609 for (uint8_t j
=0; j
<state
.resampleRatio
; j
++) {
610 mixSample(samples
++, ((int16_t *)wavBuffer
)[i
], fade
+2-volume
);
614 else if (state
.codec
== CODEC_ID_PCM_ALAW
) {
615 for (uint32_t i
=0; i
<read
; i
++) {
616 for (uint8_t j
=0; j
<state
.resampleRatio
; j
++) {
617 mixSample(samples
++, alawTable
[wavBuffer
[i
]], fade
+2-volume
);
621 else if (state
.codec
== CODEC_ID_PCM_MULAW
) {
622 for (uint32_t i
=0; i
<read
; i
++) {
623 for (uint8_t j
=0; j
<state
.resampleRatio
; j
++) {
624 mixSample(samples
++, ulawTable
[wavBuffer
[i
]], fade
+2-volume
);
629 return samples
- buffer
->data
;
633 if (result
!= FR_OK
) {
639 int WavContext::mixBuffer(AudioBuffer
*buffer
, int volume
, unsigned int fade
)
645 const unsigned int toneVolumes
[] = { 10, 8, 6, 4, 2 };
646 inline float evalVolumeRatio(int freq
, int volume
)
648 float result
= toneVolumes
[2+volume
];
650 result
= (result
* freq
* freq
) / (330 * 330);
655 int ToneContext::mixBuffer(AudioBuffer
* buffer
, int volume
, unsigned int fade
)
660 int remainingDuration
= fragment
.tone
.duration
- state
.duration
;
661 if (remainingDuration
> 0) {
663 float toneIdx
= state
.idx
;
665 if (fragment
.tone
.reset
) {
666 fragment
.tone
.reset
= 0;
671 if (fragment
.tone
.freq
!= state
.freq
) {
672 state
.freq
= fragment
.tone
.freq
;
673 state
.step
= limit
<float>(1, float(fragment
.tone
.freq
) * (float(DIM(sineValues
))/float(AUDIO_SAMPLE_RATE
)), 512);
674 state
.volume
= 1.0f
/ evalVolumeRatio(fragment
.tone
.freq
, volume
);
677 if (fragment
.tone
.freqIncr
) {
678 int freqChange
= AUDIO_BUFFER_DURATION
* fragment
.tone
.freqIncr
;
679 if (freqChange
> 0) {
680 fragment
.tone
.freq
+= freqChange
;
681 if (fragment
.tone
.freq
> BEEP_MAX_FREQ
) {
682 fragment
.tone
.freq
= BEEP_MAX_FREQ
;
686 if (fragment
.tone
.freq
> BEEP_MIN_FREQ
- freqChange
) {
687 fragment
.tone
.freq
+= freqChange
;
690 fragment
.tone
.freq
= BEEP_MIN_FREQ
;
695 if (remainingDuration
> AUDIO_BUFFER_DURATION
) {
696 duration
= AUDIO_BUFFER_DURATION
;
697 points
= AUDIO_BUFFER_SIZE
;
700 duration
= remainingDuration
;
701 points
= (duration
* AUDIO_BUFFER_SIZE
) / AUDIO_BUFFER_DURATION
;
702 unsigned int end
= toneIdx
+ (state
.step
* points
);
703 if (end
> DIM(sineValues
))
704 end
-= (end
% DIM(sineValues
));
706 end
= DIM(sineValues
);
707 points
= (float(end
) - toneIdx
) / state
.step
;
710 for (int i
=0; i
<points
; i
++) {
711 int16_t sample
= sineValues
[int(toneIdx
)] * state
.volume
;
712 mixSample(&buffer
->data
[i
], sample
, fade
);
713 toneIdx
+= state
.step
;
714 if ((unsigned int)toneIdx
>= DIM(sineValues
))
715 toneIdx
-= DIM(sineValues
);
718 if (remainingDuration
> AUDIO_BUFFER_DURATION
) {
719 state
.duration
+= AUDIO_BUFFER_DURATION
;
721 return AUDIO_BUFFER_SIZE
;
724 state
.duration
= 32000; // once the tone is finished, it's not possible to update its frequency and duration
728 remainingDuration
= fragment
.tone
.pause
- state
.pause
;
729 if (remainingDuration
> 0) {
730 result
= AUDIO_BUFFER_SIZE
;
731 state
.pause
+= min
<unsigned int>(AUDIO_BUFFER_DURATION
-duration
, fragment
.tone
.pause
);
732 if (fragment
.tone
.pause
> state
.pause
)
740 void AudioQueue::wakeup()
742 DEBUG_TIMER_START(debugTimerAudioConsume
);
743 audioConsumeCurrentBuffer();
744 DEBUG_TIMER_STOP(debugTimerAudioConsume
);
746 AudioBuffer
* buffer
;
747 while ((buffer
= buffersFifo
.getEmptyBuffer()) != 0) {
749 unsigned int fade
= 0;
752 // write silence in the buffer
753 for (uint32_t i
=0; i
<AUDIO_BUFFER_SIZE
; i
++) {
754 buffer
->data
[i
] = AUDIO_DATA_SILENCE
; /* silence */
757 // mix the priority context (only tones)
758 result
= priorityContext
.mixBuffer(buffer
, g_eeGeneral
.beepVolume
, fade
);
764 // mix the normal context (tones and wavs)
765 if (normalContext
.isEmpty() && !fragmentsFifo
.empty()) {
766 CoEnterMutexSection(audioMutex
);
767 normalContext
.setFragment(fragmentsFifo
.get());
768 CoLeaveMutexSection(audioMutex
);
770 result
= normalContext
.mixBuffer(buffer
, g_eeGeneral
.beepVolume
, g_eeGeneral
.wavVolume
, fade
);
772 size
= max(size
, result
);
776 // mix the vario context
777 result
= varioContext
.mixBuffer(buffer
, g_eeGeneral
.varioVolume
, fade
);
779 size
= max(size
, result
);
783 // mix the background context
784 if (isFunctionActive(FUNCTION_BACKGND_MUSIC
) && !isFunctionActive(FUNCTION_BACKGND_MUSIC_PAUSE
)) {
785 result
= backgroundContext
.mixBuffer(buffer
, g_eeGeneral
.backgroundVolume
, fade
);
787 size
= max(size
, result
);
791 // push the buffer if needed
793 // TRACE("pushing buffer %p", buffer);
796 #if defined(SOFTWARE_VOLUME)
797 if (currentSpeakerVolume
> 0) {
798 for (uint32_t i
=0; i
<buffer
->size
; ++i
) {
799 int32_t tmpSample
= (int32_t) ((uint32_t) (buffer
->data
[i
]) - AUDIO_DATA_SILENCE
); // conversion from uint16_t
800 buffer
->data
[i
] = (int16_t) (((tmpSample
* currentSpeakerVolume
) / VOLUME_LEVEL_MAX
) + AUDIO_DATA_SILENCE
);
802 buffersFifo
.audioPushBuffer();
805 buffersFifo
.audioPushBuffer();
809 // break the endless loop
812 DEBUG_TIMER_START(debugTimerAudioConsume
);
813 audioConsumeCurrentBuffer();
814 DEBUG_TIMER_STOP(debugTimerAudioConsume
);
818 inline unsigned int getToneLength(uint16_t len
)
820 unsigned int result
= len
; // default
821 if (g_eeGeneral
.beepLength
< 0) {
822 result
/= (1-g_eeGeneral
.beepLength
);
824 else if (g_eeGeneral
.beepLength
> 0) {
825 result
*= (1+g_eeGeneral
.beepLength
);
830 void AudioQueue::pause(uint16_t len
)
835 bool AudioQueue::isPlaying(uint8_t id
)
837 return normalContext
.hasPromptId(id
) ||
838 (isFunctionActive(FUNCTION_BACKGND_MUSIC
) && backgroundContext
.hasPromptId(id
)) ||
839 fragmentsFifo
.hasPromptId(id
);
842 void AudioQueue::playTone(uint16_t freq
, uint16_t len
, uint16_t pause
, uint8_t flags
, int8_t freqIncr
)
844 #if defined(SIMU) && !defined(SIMU_AUDIO)
848 CoEnterMutexSection(audioMutex
);
850 freq
= limit
<uint16_t>(BEEP_MIN_FREQ
, freq
, BEEP_MAX_FREQ
);
852 if (flags
& PLAY_BACKGROUND
) {
853 varioContext
.setFragment(freq
, len
, pause
, 0, 0, (flags
& PLAY_NOW
));
856 // adjust frequency and length according to the user preferences
857 freq
+= g_eeGeneral
.speakerPitch
* 15;
858 len
= getToneLength(len
);
860 if (flags
& PLAY_NOW
) {
861 if (priorityContext
.isFree()) {
862 priorityContext
.clear();
863 priorityContext
.setFragment(freq
, len
, pause
, flags
& 0x0f, freqIncr
, false);
867 fragmentsFifo
.push(AudioFragment(freq
, len
, pause
, flags
& 0x0f, freqIncr
, false));
871 CoLeaveMutexSection(audioMutex
);
875 void AudioQueue::playFile(const char * filename
, uint8_t flags
, uint8_t id
)
878 TRACE("playFile(\"%s\", flags=%x, id=%d)", filename
, flags
, id
);
879 if (strlen(filename
) > AUDIO_FILENAME_MAXLEN
) {
880 TRACE("file name too long! maximum length is %d characters", AUDIO_FILENAME_MAXLEN
);
883 #if !defined(SIMU_AUDIO)
891 if (g_eeGeneral
.beepMode
== e_mode_quiet
)
894 if (strlen(filename
) > AUDIO_FILENAME_MAXLEN
) {
895 POPUP_WARNING(STR_PATH_TOO_LONG
);
899 CoEnterMutexSection(audioMutex
);
901 if (flags
& PLAY_BACKGROUND
) {
902 backgroundContext
.clear();
903 backgroundContext
.setFragment(filename
, 0, id
);
906 fragmentsFifo
.push(AudioFragment(filename
, flags
& 0x0f, id
));
909 CoLeaveMutexSection(audioMutex
);
912 void AudioQueue::stopPlay(uint8_t id
)
915 TRACE("stopPlay(id=%d)", id
);
918 #if defined(SIMU) && !defined(SIMU_AUDIO)
922 CoEnterMutexSection(audioMutex
);
924 fragmentsFifo
.removePromptById(id
);
925 backgroundContext
.stop(id
);
927 CoLeaveMutexSection(audioMutex
);
930 void AudioQueue::stopSD()
932 sdAvailableSystemAudioFiles
.reset();
934 playTone(0, 0, 100, PLAY_NOW
); // insert a 100ms pause
939 void AudioQueue::stopAll()
942 CoEnterMutexSection(audioMutex
);
943 priorityContext
.clear();
944 normalContext
.clear();
945 CoLeaveMutexSection(audioMutex
);
948 void AudioQueue::flush()
950 CoEnterMutexSection(audioMutex
);
951 fragmentsFifo
.clear();
952 varioContext
.clear();
953 backgroundContext
.clear();
954 CoLeaveMutexSection(audioMutex
);
957 void audioPlay(unsigned int index
, uint8_t id
)
959 if (g_eeGeneral
.beepMode
>= -1) {
960 char filename
[AUDIO_FILENAME_MAXLEN
+1];
961 if (isAudioFileReferenced(index
, filename
)) {
962 audioQueue
.playFile(filename
, 0, id
);
969 if (g_eeGeneral
.beepMode
== e_mode_all
) {
970 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 40, 20, PLAY_NOW
);
973 if (g_eeGeneral
.hapticMode
== e_mode_all
) {
974 haptic
.play(5, 0, PLAY_NOW
);
981 if (g_eeGeneral
.beepMode
>= e_mode_nokeys
) {
982 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 160, 20, PLAY_NOW
);
986 if (g_eeGeneral
.hapticMode
>= e_mode_nokeys
) {
987 haptic
.play(15, 3, PLAY_NOW
);
992 void audioTrimPress(int value
)
994 if (g_eeGeneral
.beepMode
>= e_mode_nokeys
) {
995 value
= limit(TRIM_MIN
, value
, TRIM_MAX
) * 8 + 120*16;
996 audioQueue
.playTone(value
, 40, 20, PLAY_NOW
);
1000 void audioTimerCountdown(uint8_t timer
, int value
)
1002 if (g_model
.timers
[timer
].countdownBeep
== COUNTDOWN_VOICE
) {
1003 if (value
>= 0 && value
<= TIMER_COUNTDOWN_START(timer
)) {
1004 playNumber(value
, 0, 0, 0);
1006 else if (value
== 30 || value
== 20) {
1007 playDuration(value
, 0, 0);
1010 else if (g_model
.timers
[timer
].countdownBeep
== COUNTDOWN_BEEPS
) {
1012 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 150, 300, 20, PLAY_NOW
);
1014 else if (value
> 0 && value
<= TIMER_COUNTDOWN_START(timer
)) {
1015 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 150, 100, 20, PLAY_NOW
);
1017 else if (value
== 30) {
1018 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 150, 120, 20, PLAY_REPEAT(2));
1020 else if (value
== 20) {
1021 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 150, 120, 20, PLAY_REPEAT(1));
1023 else if (value
== 10) {
1024 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 150, 120, 20, PLAY_NOW
);
1028 else if (g_model
.timers
[timer
].countdownBeep
== COUNTDOWN_HAPTIC
) {
1030 haptic
.play(15, 3, PLAY_NOW
);
1032 else if (value
> 0 && value
<= TIMER_COUNTDOWN_START(timer
)) {
1033 haptic
.play(10, 0, PLAY_NOW
);
1035 else if (value
== 30) {
1036 haptic
.play(10, 3, PLAY_REPEAT(2) | PLAY_NOW
);
1038 else if (value
== 20) {
1039 haptic
.play(10, 3, PLAY_REPEAT(1) | PLAY_NOW
);
1041 else if (value
== 10) {
1042 haptic
.play(10, 3, PLAY_NOW
);
1048 void audioEvent(unsigned int index
)
1050 if (index
== AU_NONE
)
1054 haptic
.event(index
); // do this before audio to help sync timings
1057 if (index
<= AU_ERROR
) {
1058 if (g_eeGeneral
.alarmsFlash
) {
1059 flashCounter
= FLASH_DURATION
;
1063 if (g_eeGeneral
.beepMode
>= e_mode_nokeys
|| (g_eeGeneral
.beepMode
>= e_mode_alarms
&& index
<= AU_ERROR
)) {
1065 char filename
[AUDIO_FILENAME_MAXLEN
+ 1];
1066 if (index
< AU_SPECIAL_SOUND_FIRST
&& isAudioFileReferenced(index
, filename
)) {
1067 audioQueue
.stopPlay(ID_PLAY_PROMPT_BASE
+ index
);
1068 audioQueue
.playFile(filename
, 0, ID_PLAY_PROMPT_BASE
+ index
);
1074 audioQueue
.playTone(2250, 80, 20, PLAY_REPEAT(2));
1076 case AU_TX_BATTERY_LOW
:
1077 #if defined(PCBSKY9X)
1078 case AU_TX_MAH_HIGH
:
1079 case AU_TX_TEMP_HIGH
:
1081 audioQueue
.playTone(1950, 160, 20, PLAY_REPEAT(2), 1);
1082 audioQueue
.playTone(2550, 160, 20, PLAY_REPEAT(2), -1);
1084 case AU_THROTTLE_ALERT
:
1085 case AU_SWITCH_ALERT
:
1087 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 200, 20, PLAY_NOW
);
1089 case AU_TRIM_MIDDLE
:
1090 audioQueue
.playTone(120*16, 80, 20, PLAY_NOW
);
1093 audioQueue
.playTone(TRIM_MIN
*8 + 120*16, 80, 20, PLAY_NOW
);
1096 audioQueue
.playTone(TRIM_MAX
*8 + 120*16, 80, 20, PLAY_NOW
);
1099 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 80, 20, PLAY_NOW
);
1102 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 160, 20, PLAY_NOW
);
1105 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 200, 20, PLAY_NOW
);
1107 // TODO remove all these ones
1108 case AU_STICK1_MIDDLE
:
1109 case AU_STICK2_MIDDLE
:
1110 case AU_STICK3_MIDDLE
:
1111 case AU_STICK4_MIDDLE
:
1112 case AU_POT1_MIDDLE
:
1113 case AU_POT2_MIDDLE
:
1115 case AU_POT3_MIDDLE
:
1116 case AU_POT4_MIDDLE
:
1118 #if defined(PCBTARANIS) || defined(PCBHORUS)
1119 case AU_SLIDER1_MIDDLE
:
1120 case AU_SLIDER2_MIDDLE
:
1122 case AU_SLIDER3_MIDDLE
:
1123 case AU_SLIDER4_MIDDLE
:
1126 case AU_POT3_MIDDLE
:
1128 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 80, 20, PLAY_NOW
);
1130 case AU_MIX_WARNING_1
:
1131 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1440, 48, 32);
1133 case AU_MIX_WARNING_2
:
1134 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1560, 48, 32, PLAY_REPEAT(1));
1136 case AU_MIX_WARNING_3
:
1137 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1680, 48, 32, PLAY_REPEAT(2));
1139 case AU_TIMER1_ELAPSED
:
1140 case AU_TIMER2_ELAPSED
:
1141 case AU_TIMER3_ELAPSED
:
1142 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 150, 300, 20, PLAY_NOW
);
1144 case AU_RSSI_ORANGE
:
1145 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 800, 20, PLAY_NOW
);
1148 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1800, 800, 20, PLAY_REPEAT(1) | PLAY_NOW
);
1151 audioQueue
.playTone(450, 160, 40, PLAY_REPEAT(2), 1);
1153 case AU_SPECIAL_SOUND_BEEP1
:
1154 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 60, 20);
1156 case AU_SPECIAL_SOUND_BEEP2
:
1157 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 120, 20);
1159 case AU_SPECIAL_SOUND_BEEP3
:
1160 audioQueue
.playTone(BEEP_DEFAULT_FREQ
, 200, 20);
1162 case AU_SPECIAL_SOUND_WARN1
:
1163 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 600, 120, 40, PLAY_REPEAT(2));
1165 case AU_SPECIAL_SOUND_WARN2
:
1166 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 900, 120, 40, PLAY_REPEAT(2));
1168 case AU_SPECIAL_SOUND_CHEEP
:
1169 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 900, 80, 20, PLAY_REPEAT(2), 2);
1171 case AU_SPECIAL_SOUND_RING
:
1172 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 750, 40, 20, PLAY_REPEAT(10));
1173 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 750, 40, 80, PLAY_REPEAT(1));
1174 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 750, 40, 20, PLAY_REPEAT(10));
1176 case AU_SPECIAL_SOUND_SCIFI
:
1177 audioQueue
.playTone(2550, 80, 20, PLAY_REPEAT(2), -1);
1178 audioQueue
.playTone(1950, 80, 20, PLAY_REPEAT(2), 1);
1179 audioQueue
.playTone(2250, 80, 20, 0);
1181 case AU_SPECIAL_SOUND_ROBOT
:
1182 audioQueue
.playTone(2250, 40, 20, PLAY_REPEAT(1));
1183 audioQueue
.playTone(1650, 120, 20, PLAY_REPEAT(1));
1184 audioQueue
.playTone(2550, 120, 20, PLAY_REPEAT(1));
1186 case AU_SPECIAL_SOUND_CHIRP
:
1187 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1200, 40, 20, PLAY_REPEAT(2));
1188 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1620, 40, 20, PLAY_REPEAT(3));
1190 case AU_SPECIAL_SOUND_TADA
:
1191 audioQueue
.playTone(1650, 80, 40);
1192 audioQueue
.playTone(2850, 80, 40);
1193 audioQueue
.playTone(3450, 64, 36, PLAY_REPEAT(2));
1195 case AU_SPECIAL_SOUND_CRICKET
:
1196 audioQueue
.playTone(2550, 40, 80, PLAY_REPEAT(3));
1197 audioQueue
.playTone(2550, 40, 160, PLAY_REPEAT(1));
1198 audioQueue
.playTone(2550, 40, 80, PLAY_REPEAT(3));
1200 case AU_SPECIAL_SOUND_SIREN
:
1201 audioQueue
.playTone(450, 160, 40, PLAY_REPEAT(2), 2);
1203 case AU_SPECIAL_SOUND_ALARMC
:
1204 audioQueue
.playTone(1650, 32, 68, PLAY_REPEAT(2));
1205 audioQueue
.playTone(2250, 64, 156, PLAY_REPEAT(1));
1206 audioQueue
.playTone(1650, 64, 76, PLAY_REPEAT(2));
1207 audioQueue
.playTone(2250, 32, 168, PLAY_REPEAT(1));
1209 case AU_SPECIAL_SOUND_RATATA
:
1210 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 40, 80, PLAY_REPEAT(10));
1212 case AU_SPECIAL_SOUND_TICK
:
1213 audioQueue
.playTone(BEEP_DEFAULT_FREQ
+ 1500, 40, 400, PLAY_REPEAT(2));
1222 void pushUnit(uint8_t unit
, uint8_t idx
, uint8_t id
)
1224 if (unit
< DIM(unitsFilenames
)) {
1225 char path
[AUDIO_FILENAME_MAXLEN
+1];
1226 char * tmp
= strAppendSystemAudioPath(path
);
1227 tmp
= strAppendStringWithIndex(tmp
, unitsFilenames
[unit
], idx
);
1228 strcpy(tmp
, SOUNDS_EXT
);
1229 audioQueue
.playFile(path
, 0, id
);
1232 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.
1237 void pushPrompt(uint16_t prompt
, uint8_t id
)
1240 char filename
[AUDIO_FILENAME_MAXLEN
+1];
1241 char * str
= strAppendSystemAudioPath(filename
);
1242 strcpy(str
, "0000" SOUNDS_EXT
);
1243 for (int8_t i
=3; i
>=0; i
--) {
1244 str
[i
] = '0' + (prompt
%10);
1247 audioQueue
.playFile(filename
, 0, id
);