fix models list reload after USB mass storage connection (#5963)
[opentx.git] / radio / src / audio_arm.cpp
blob06ea7f6ebea582119d4e15118cca975f0759e418
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 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,
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 "hour",
161 "minute",
162 "second",
165 const char * const audioFilenames[] = {
166 "hello",
167 "bye",
168 "thralert",
169 "swalert",
170 "baddata",
171 "lowbatt",
172 "inactiv",
173 "rssi_org",
174 "rssi_red",
175 "swr_red",
176 "telemko",
177 "telemok",
178 "trainko",
179 "trainok",
180 "sensorko",
181 "servoko",
182 "rxko",
183 "modelpwr",
184 #if defined(PCBSKY9X)
185 "highmah",
186 "hightemp",
187 #endif
188 "error",
189 "warning1",
190 "warning2",
191 "warning3",
192 "midtrim",
193 "mintrim",
194 "maxtrim",
195 "midstck1",
196 "midstck2",
197 "midstck3",
198 "midstck4",
199 #if defined(PCBTARANIS) || defined(PCBHORUS)
200 "midpot1",
201 "midpot2",
202 #if defined(PCBX9E)
203 "midpot3",
204 "midpot4",
205 #endif
206 "midslid1",
207 "midslid2",
208 #if defined(PCBX9E)
209 "midslid3",
210 "midslid4",
211 #endif
212 #else
213 "midpot1",
214 "midpot2",
215 "midpot3",
216 #endif
217 "mixwarn1",
218 "mixwarn2",
219 "mixwarn3",
220 "timovr1",
221 "timovr2",
222 "timovr3"
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];
255 FILINFO fno;
256 DIR dir;
258 sdAvailableSystemAudioFiles.reset();
260 char * filename = strAppendSystemAudioPath(path);
261 *(filename-1) = '\0';
263 FRESULT res = f_opendir(&dir, path); /* Open the directory */
264 if (res == FR_OK) {
265 for (;;) {
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);
277 break;
281 f_closedir(&dir);
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));
292 *result++ = '/';
293 *result = '\0';
294 return result;
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);
312 *str++ = 'S';
313 *str++ = 'A' + swinfo.quot;
314 const char * positions[] = { "-up", "-mid", "-down" };
315 strcpy(str, positions[swinfo.rem]);
317 else {
318 div_t swinfo = div(int(index - SWSRC_FIRST_MULTIPOS_SWITCH), XPOTS_MULTIPOS_COUNT);
319 *str++ = 'S';
320 *str++ = '1' + swinfo.quot;
321 *str++ = '1' + swinfo.rem;
322 *str = '\0';
324 #else
325 int len = STR_VSWITCHES[0];
326 strncpy(str, &STR_VSWITCHES[1+(len*index)], len);
327 str += len;
328 *str = '\0';
329 #endif
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)
338 *str++ = 'L';
339 if (index >= 9) {
340 div_t qr = div(index+1, 10);
341 *str++ = '0' + qr.quot;
342 *str++ = '0' + qr.rem;
344 else {
345 *str++ = '1' + index;
347 #else
348 int len = STR_VSWITCHES[0];
349 strncpy(str, &STR_VSWITCHES[1+len*(index+SWSRC_FIRST_LOGICAL_SWITCH)], len);
350 str += len;
351 #endif
353 strcpy(str, suffixes[event]);
354 strcat(str, SOUNDS_EXT);
357 void referenceModelAudioFiles()
359 char path[AUDIO_FILENAME_MAXLEN+1];
360 FILINFO fno;
361 DIR dir;
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 */
371 if (res == FR_OK) {
372 for (;;) {
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);
376 bool found = false;
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));
389 found = true;
390 TRACE("\tfound: %s", filename);
391 break;
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);
402 found = true;
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));
414 found = true;
415 TRACE("\tfound: %s", filename);
416 break;
421 f_closedir(&dir);
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);
436 return true;
439 else if (category == PHASE_AUDIO_CATEGORY) {
440 if (sdAvailablePhaseAudioFiles.getBit(INDEX_PHASE_AUDIO_FILE(index, event))) {
441 getPhaseAudioFile(filename, index, event);
442 return true;
445 else if (category == SWITCH_AUDIO_CATEGORY) {
446 if (sdAvailableSwitchAudioFiles.getBit(index)) {
447 getSwitchAudioFile(filename, SWSRC_FIRST_SWITCH+index);
448 return true;
451 else if (category == LOGICAL_SWITCH_AUDIO_CATEGORY) {
452 if (sdAvailableLogicalSwitchAudioFiles.getBit(INDEX_LOGICAL_SWITCH_AUDIO_FILE(index, event))) {
453 getLogicalSwitchAudioFile(filename, index, event);
454 return true;
458 return false;
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);
472 void playModelName()
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()
493 : buffersFifo(),
494 _started(false),
495 normalContext(),
496 backgroundContext(),
497 priorityContext(),
498 varioContext(),
499 fragmentsFifo()
503 #define CODEC_ID_PCM_S16LE 1
504 #define CODEC_ID_PCM_ALAW 6
505 #define CODEC_ID_PCM_MULAW 7
507 #if !defined(SIMU)
508 void audioTask(void * pdata)
510 while (!audioQueue.started()) {
511 CoTickDelay(1);
514 setSampleRate(AUDIO_SAMPLE_RATE);
516 #if defined(PCBX12S)
517 // The audio amp needs ~2s to start
518 CoTickDelay(500); // 1s
519 #endif
521 if (!unexpectedShutdown) {
522 AUDIO_HELLO();
525 while (1) {
526 DEBUG_TIMER_SAMPLE(debugTimerAudioIterval);
527 DEBUG_TIMER_START(debugTimerAudioDuration);
528 audioQueue.wakeup();
529 DEBUG_TIMER_STOP(debugTimerAudioDuration);
530 CoTickDelay(2/*4ms*/);
533 #endif
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);
540 #if defined(SDCARD)
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;
548 UINT read = 0;
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;
567 else {
568 result = FR_DENIED;
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];
579 state.size = size;
581 else {
582 result = FR_DENIED;
585 else {
586 result = FR_DENIED;
591 if (result == FR_OK) {
592 read = 0;
593 result = f_read(&state.file, wavBuffer, state.readSize, &read);
594 if (result == FR_OK) {
595 if (read > state.size) {
596 read = state.size;
598 state.size -= read;
600 if (read != state.readSize) {
601 f_close(&state.file);
602 fragment.clear();
605 audio_data_t * samples = buffer->data;
606 if (state.codec == CODEC_ID_PCM_S16LE) {
607 read /= 2;
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) {
634 clear();
636 return 0;
638 #else
639 int WavContext::mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade)
641 return 0;
643 #endif
645 const unsigned int toneVolumes[] = { 10, 8, 6, 4, 2 };
646 inline float evalVolumeRatio(int freq, int volume)
648 float result = toneVolumes[2+volume];
649 if (freq < 330) {
650 result = (result * freq * freq) / (330 * 330);
652 return result;
655 int ToneContext::mixBuffer(AudioBuffer * buffer, int volume, unsigned int fade)
657 int duration = 0;
658 int result = 0;
660 int remainingDuration = fragment.tone.duration - state.duration;
661 if (remainingDuration > 0) {
662 int points;
663 float toneIdx = state.idx;
665 if (fragment.tone.reset) {
666 fragment.tone.reset = 0;
667 state.duration = 0;
668 state.pause = 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;
685 else {
686 if (fragment.tone.freq > BEEP_MIN_FREQ - freqChange) {
687 fragment.tone.freq += freqChange;
689 else {
690 fragment.tone.freq = BEEP_MIN_FREQ;
695 if (remainingDuration > AUDIO_BUFFER_DURATION) {
696 duration = AUDIO_BUFFER_DURATION;
697 points = AUDIO_BUFFER_SIZE;
699 else {
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));
705 else
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;
720 state.idx = toneIdx;
721 return AUDIO_BUFFER_SIZE;
723 else {
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)
733 return result;
736 clear();
737 return result;
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) {
748 int result;
749 unsigned int fade = 0;
750 int size = 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);
759 if (result > 0) {
760 size = result;
761 fade += 1;
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);
771 if (result > 0) {
772 size = max(size, result);
773 fade += 1;
776 // mix the vario context
777 result = varioContext.mixBuffer(buffer, g_eeGeneral.varioVolume, fade);
778 if (result > 0) {
779 size = max(size, result);
780 fade += 1;
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);
786 if (result > 0) {
787 size = max(size, result);
791 // push the buffer if needed
792 if (size > 0) {
793 // TRACE("pushing buffer %p", buffer);
794 buffer->size = size;
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();
804 #else
805 buffersFifo.audioPushBuffer();
806 #endif
808 else {
809 // break the endless loop
810 break;
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);
827 return result;
830 void AudioQueue::pause(uint16_t len)
832 playTone(0, 0, 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)
845 return;
846 #endif
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));
855 else {
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);
866 else {
867 fragmentsFifo.push(AudioFragment(freq, len, pause, flags & 0x0f, freqIncr, false));
871 CoLeaveMutexSection(audioMutex);
874 #if defined(SDCARD)
875 void AudioQueue::playFile(const char * filename, uint8_t flags, uint8_t id)
877 #if defined(SIMU)
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);
881 return;
883 #if !defined(SIMU_AUDIO)
884 return;
885 #endif
886 #endif
888 if (!sdMounted())
889 return;
891 if (g_eeGeneral.beepMode == e_mode_quiet)
892 return;
894 if (strlen(filename) > AUDIO_FILENAME_MAXLEN) {
895 POPUP_WARNING(STR_PATH_TOO_LONG);
896 return;
899 CoEnterMutexSection(audioMutex);
901 if (flags & PLAY_BACKGROUND) {
902 backgroundContext.clear();
903 backgroundContext.setFragment(filename, 0, id);
905 else {
906 fragmentsFifo.push(AudioFragment(filename, flags & 0x0f, id));
909 CoLeaveMutexSection(audioMutex);
912 void AudioQueue::stopPlay(uint8_t id)
914 #if defined(SIMU)
915 TRACE("stopPlay(id=%d)", id);
916 #endif
918 #if defined(SIMU) && !defined(SIMU_AUDIO)
919 return;
920 #endif
922 CoEnterMutexSection(audioMutex);
924 fragmentsFifo.removePromptById(id);
925 backgroundContext.stop(id);
927 CoLeaveMutexSection(audioMutex);
930 void AudioQueue::stopSD()
932 sdAvailableSystemAudioFiles.reset();
933 stopAll();
934 playTone(0, 0, 100, PLAY_NOW); // insert a 100ms pause
937 #endif
939 void AudioQueue::stopAll()
941 flush();
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);
967 void audioKeyPress()
969 if (g_eeGeneral.beepMode == e_mode_all) {
970 audioQueue.playTone(BEEP_DEFAULT_FREQ, 40, 20, PLAY_NOW);
972 #if defined(HAPTIC)
973 if (g_eeGeneral.hapticMode == e_mode_all) {
974 haptic.play(5, 0, PLAY_NOW);
976 #endif
979 void audioKeyError()
981 if (g_eeGeneral.beepMode >= e_mode_nokeys) {
982 audioQueue.playTone(BEEP_DEFAULT_FREQ, 160, 20, PLAY_NOW);
985 #if defined(HAPTIC)
986 if (g_eeGeneral.hapticMode >= e_mode_nokeys) {
987 haptic.play(15, 3, PLAY_NOW);
989 #endif
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) {
1011 if (value == 0) {
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);
1027 #if defined(HAPTIC)
1028 else if (g_model.timers[timer].countdownBeep == COUNTDOWN_HAPTIC) {
1029 if (value == 0) {
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);
1045 #endif
1048 void audioEvent(unsigned int index)
1050 if (index == AU_NONE)
1051 return;
1053 #if defined(HAPTIC)
1054 haptic.event(index); // do this before audio to help sync timings
1055 #endif
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)) {
1064 #if defined(SDCARD)
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);
1069 return;
1071 #endif
1072 switch (index) {
1073 case AU_INACTIVITY:
1074 audioQueue.playTone(2250, 80, 20, PLAY_REPEAT(2));
1075 break;
1076 case AU_TX_BATTERY_LOW:
1077 #if defined(PCBSKY9X)
1078 case AU_TX_MAH_HIGH:
1079 case AU_TX_TEMP_HIGH:
1080 #endif
1081 audioQueue.playTone(1950, 160, 20, PLAY_REPEAT(2), 1);
1082 audioQueue.playTone(2550, 160, 20, PLAY_REPEAT(2), -1);
1083 break;
1084 case AU_THROTTLE_ALERT:
1085 case AU_SWITCH_ALERT:
1086 case AU_ERROR:
1087 audioQueue.playTone(BEEP_DEFAULT_FREQ, 200, 20, PLAY_NOW);
1088 break;
1089 case AU_TRIM_MIDDLE:
1090 audioQueue.playTone(120*16, 80, 20, PLAY_NOW);
1091 break;
1092 case AU_TRIM_MIN:
1093 audioQueue.playTone(TRIM_MIN*8 + 120*16, 80, 20, PLAY_NOW);
1094 break;
1095 case AU_TRIM_MAX:
1096 audioQueue.playTone(TRIM_MAX*8 + 120*16, 80, 20, PLAY_NOW);
1097 break;
1098 case AU_WARNING1:
1099 audioQueue.playTone(BEEP_DEFAULT_FREQ, 80, 20, PLAY_NOW);
1100 break;
1101 case AU_WARNING2:
1102 audioQueue.playTone(BEEP_DEFAULT_FREQ, 160, 20, PLAY_NOW);
1103 break;
1104 case AU_WARNING3:
1105 audioQueue.playTone(BEEP_DEFAULT_FREQ, 200, 20, PLAY_NOW);
1106 break;
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:
1114 #if defined(PCBX9E)
1115 case AU_POT3_MIDDLE:
1116 case AU_POT4_MIDDLE:
1117 #endif
1118 #if defined(PCBTARANIS) || defined(PCBHORUS)
1119 case AU_SLIDER1_MIDDLE:
1120 case AU_SLIDER2_MIDDLE:
1121 #if defined(PCBX9E)
1122 case AU_SLIDER3_MIDDLE:
1123 case AU_SLIDER4_MIDDLE:
1124 #endif
1125 #else
1126 case AU_POT3_MIDDLE:
1127 #endif
1128 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 80, 20, PLAY_NOW);
1129 break;
1130 case AU_MIX_WARNING_1:
1131 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1440, 48, 32);
1132 break;
1133 case AU_MIX_WARNING_2:
1134 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1560, 48, 32, PLAY_REPEAT(1));
1135 break;
1136 case AU_MIX_WARNING_3:
1137 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1680, 48, 32, PLAY_REPEAT(2));
1138 break;
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);
1143 break;
1144 case AU_RSSI_ORANGE:
1145 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 800, 20, PLAY_NOW);
1146 break;
1147 case AU_RSSI_RED:
1148 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1800, 800, 20, PLAY_REPEAT(1) | PLAY_NOW);
1149 break;
1150 case AU_RAS_RED:
1151 audioQueue.playTone(450, 160, 40, PLAY_REPEAT(2), 1);
1152 break;
1153 case AU_SPECIAL_SOUND_BEEP1:
1154 audioQueue.playTone(BEEP_DEFAULT_FREQ, 60, 20);
1155 break;
1156 case AU_SPECIAL_SOUND_BEEP2:
1157 audioQueue.playTone(BEEP_DEFAULT_FREQ, 120, 20);
1158 break;
1159 case AU_SPECIAL_SOUND_BEEP3:
1160 audioQueue.playTone(BEEP_DEFAULT_FREQ, 200, 20);
1161 break;
1162 case AU_SPECIAL_SOUND_WARN1:
1163 audioQueue.playTone(BEEP_DEFAULT_FREQ + 600, 120, 40, PLAY_REPEAT(2));
1164 break;
1165 case AU_SPECIAL_SOUND_WARN2:
1166 audioQueue.playTone(BEEP_DEFAULT_FREQ + 900, 120, 40, PLAY_REPEAT(2));
1167 break;
1168 case AU_SPECIAL_SOUND_CHEEP:
1169 audioQueue.playTone(BEEP_DEFAULT_FREQ + 900, 80, 20, PLAY_REPEAT(2), 2);
1170 break;
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));
1175 break;
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);
1180 break;
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));
1185 break;
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));
1189 break;
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));
1194 break;
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));
1199 break;
1200 case AU_SPECIAL_SOUND_SIREN:
1201 audioQueue.playTone(450, 160, 40, PLAY_REPEAT(2), 2);
1202 break;
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));
1208 break;
1209 case AU_SPECIAL_SOUND_RATATA:
1210 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 40, 80, PLAY_REPEAT(10));
1211 break;
1212 case AU_SPECIAL_SOUND_TICK:
1213 audioQueue.playTone(BEEP_DEFAULT_FREQ + 1500, 40, 400, PLAY_REPEAT(2));
1214 break;
1215 default:
1216 break;
1221 #if defined(SDCARD)
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);
1231 else {
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.
1235 #endif
1237 void pushPrompt(uint16_t prompt, uint8_t id)
1239 #if defined(SDCARD)
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);
1245 prompt /= 10;
1247 audioQueue.playFile(filename, 0, id);
1248 #endif