Fix doc path
[opentx.git] / radio / src / audio_avr.cpp
blob5dbc464d0b907fe658fb2ba0ffd611d6dcb8dd8f
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"
23 audioQueue::audioQueue()
25 toneTimeLeft = 0;
26 tonePause = 0;
27 tone2TimeLeft = 0;
29 t_queueRidx = 0;
30 t_queueWidx = 0;
34 // heartbeat is responsibile for issueing the audio tones and general square waves
35 // it is essentially the life of the class.
36 // it is called every 10ms
37 void audioQueue::heartbeat()
39 #if defined(SIMU)
40 return;
41 #else
42 if (toneTimeLeft > 0) {
43 if (toneFreq == 0) { //pause only events
44 speakerOff();
46 else {
47 #if defined(CPUM2560)
48 if (toneFreq) {
49 OCR4A = (5000 / toneFreq); // sticking with old values approx 20(abs. min) to 90, 60 being the default tone(?).
50 speakerOn();
52 #endif
53 toneFreq += toneFreqIncr;
55 toneTimeLeft--; //time gets counted down
57 else {
58 if (tonePause > 0) {
59 speakerOff();
60 tonePause--; //time gets counted down
62 else if (t_queueRidx != t_queueWidx) {
63 toneFreq = queueToneFreq[t_queueRidx];
64 toneTimeLeft = queueToneLength[t_queueRidx];
65 toneFreqIncr = queueToneFreqIncr[t_queueRidx];
66 tonePause = queueTonePause[t_queueRidx];
67 if (!queueToneRepeat[t_queueRidx]--) {
68 t_queueRidx = (t_queueRidx + 1) & (AUDIO_QUEUE_LENGTH-1);
71 else {
72 if (tone2TimeLeft > 0) {
73 #if defined(CPUM2560)
74 if (tone2Freq) {
75 OCR4A = (5000 / tone2Freq); // sticking with old values approx 20(abs. min) to 90, 60 being the default tone(?).
76 speakerOn();
78 #else
79 toneFreq = tone2Freq;
80 #endif
81 tone2TimeLeft--; //time gets counted down
83 else {
84 speakerOff();
88 #endif // defined(SIMU)
91 inline uint8_t audioQueue::getToneLength(uint8_t tLen)
93 uint8_t result = tLen; // default
94 if (g_eeGeneral.beepLength < 0) {
95 result /= (1-g_eeGeneral.beepLength);
97 if (g_eeGeneral.beepLength > 0) {
98 result *= (1+g_eeGeneral.beepLength);
100 return result;
103 void audioQueue::pause(uint8_t tLen)
105 play(0, tLen, 5); // a pause
108 void audioQueue::play(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tFlags)
110 if (tFlags & PLAY_BACKGROUND) {
111 tone2Freq = tFreq;
112 tone2TimeLeft = tLen;
114 else {
115 int8_t tFreqIncr = (tFlags >> 6);
116 if (tFreqIncr == 3) tFreqIncr = -1;
118 tFreq += g_eeGeneral.speakerPitch + BEEP_OFFSET; // add pitch compensator
119 tLen = getToneLength(tLen);
121 if ((tFlags & PLAY_NOW) || (!busy() && empty())) {
122 toneFreq = tFreq;
123 toneTimeLeft = tLen;
124 tonePause = tPause;
125 toneFreqIncr = tFreqIncr;
126 t_queueWidx = t_queueRidx;
128 else {
129 tFlags++;
132 tFlags &= 0x0f;
133 if (tFlags) {
134 uint8_t next_queueWidx = (t_queueWidx + 1) & (AUDIO_QUEUE_LENGTH-1);
135 if (next_queueWidx != t_queueRidx) {
136 queueToneFreq[t_queueWidx] = tFreq;
137 queueToneLength[t_queueWidx] = tLen;
138 queueTonePause[t_queueWidx] = tPause;
139 queueToneRepeat[t_queueWidx] = tFlags - 1;
140 queueToneFreqIncr[t_queueWidx] = tFreqIncr;
141 t_queueWidx = next_queueWidx;
147 void audioQueue::event(uint8_t e)
149 #if defined(HAPTIC)
150 haptic.event(e); //do this before audio to help sync timings
151 #endif
153 if (e <= AU_ERROR || (e >= AU_WARNING1 && e < AU_SPECIAL_SOUND_FIRST)) {
154 if (g_eeGeneral.alarmsFlash) {
155 flashCounter = FLASH_DURATION;
159 if (g_eeGeneral.beepMode >= e_mode_nokeys || (g_eeGeneral.beepMode >= e_mode_alarms && e <= AU_ERROR)) {
160 if (e < AU_SPECIAL_SOUND_FIRST || empty()) {
161 // TODO when VOICE enable some cases here are not needed!
162 switch (e) {
163 #if !defined(VOICE)
164 case AU_TX_BATTERY_LOW:
165 if (empty()) {
166 play(60, 20, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(1));
167 play(80, 20, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(-1));
169 break;
170 #endif
171 case AU_SPECIAL_SOUND_RING:
172 play(BEEP_DEFAULT_FREQ+25, 5, 2, PLAY_REPEAT(10));
173 play(BEEP_DEFAULT_FREQ+25, 5, 10, PLAY_REPEAT(1));
174 play(BEEP_DEFAULT_FREQ+25, 5, 2, PLAY_REPEAT(10));
175 break;
176 case AU_SPECIAL_SOUND_SCIFI:
177 play(80, 10, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(-1));
178 play(60, 10, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(1));
179 play(70, 10, 1);
180 break;
181 case AU_SPECIAL_SOUND_ROBOT:
182 play(70, 5, 1, PLAY_REPEAT(1));
183 play(50, 15, 2, PLAY_REPEAT(1));
184 play(80, 15, 2, PLAY_REPEAT(1));
185 break;
186 case AU_SPECIAL_SOUND_CHIRP:
187 play(BEEP_DEFAULT_FREQ+40, 5, 1, PLAY_REPEAT(2));
188 play(BEEP_DEFAULT_FREQ+54, 5, 1, PLAY_REPEAT(3));
189 break;
190 case AU_SPECIAL_SOUND_TADA:
191 play(50, 5, 5);
192 play(90, 5, 5);
193 play(110, 3, 4, PLAY_REPEAT(2));
194 break;
195 case AU_SPECIAL_SOUND_CRICKET:
196 play(80, 5, 10, PLAY_REPEAT(3));
197 play(80, 5, 20, PLAY_REPEAT(1));
198 play(80, 5, 10, PLAY_REPEAT(3));
199 break;
200 case AU_SPECIAL_SOUND_ALARMC:
201 play(50, 4, 10, PLAY_REPEAT(2));
202 play(70, 8, 20, PLAY_REPEAT(1));
203 play(50, 8, 10, PLAY_REPEAT(2));
204 play(70, 4, 20, PLAY_REPEAT(1));
205 break;
206 default:
208 static const pm_uint8_t singleSounds[] PROGMEM = {
209 70, 10, 2, PLAY_REPEAT(2)|PLAY_NOW, // INACTIVITY
210 BEEP_DEFAULT_FREQ, 40, 1, PLAY_NOW, // ERROR
211 BEEP_DEFAULT_FREQ, 10, 1, PLAY_NOW, // WARNING1
212 BEEP_DEFAULT_FREQ, 20, 1, PLAY_NOW, // WARNING2
213 BEEP_DEFAULT_FREQ, 30, 1, PLAY_NOW, // WARNING3
214 60, 10, 2, PLAY_NOW, // TRIM_MIDDLE
215 BEEP_DEFAULT_FREQ + 50, 10, 1, PLAY_NOW, // POT_STICK_MIDDLE
216 BEEP_DEFAULT_FREQ + 50, 6, 0, 0, // MIX_WARNING_1
217 BEEP_DEFAULT_FREQ + 52, 6, 3, PLAY_REPEAT(1), // MIX_WARNING_2
218 BEEP_DEFAULT_FREQ + 54, 6, 3, PLAY_REPEAT(2), // MIX_WARNING_3
219 BEEP_DEFAULT_FREQ, 10, 1, 0, // FRSKY_BEEP1
220 BEEP_DEFAULT_FREQ, 20, 1, 0, // FRSKY_BEEP2
221 BEEP_DEFAULT_FREQ, 30, 1, 0, // FRSKY_BEEP3
222 BEEP_DEFAULT_FREQ+20, 15, 5, PLAY_REPEAT(2), // FRSKY_WARN1
223 BEEP_DEFAULT_FREQ+30, 15, 5, PLAY_REPEAT(2), // FRSKY_WARN2
224 BEEP_DEFAULT_FREQ+30, 10, 2, PLAY_REPEAT(2)|PLAY_INCREMENT(2), // FRSKY_CHEEP
225 BEEP_DEFAULT_FREQ+50, 5, 10, PLAY_REPEAT(10), // FRSKY_RATATA
226 BEEP_DEFAULT_FREQ+50, 5, 50, PLAY_REPEAT(2), // FRSKY_TICK
227 10, 20, 5, PLAY_REPEAT(2)|PLAY_INCREMENT(1), // FRSKY_SIREN
230 const pm_uint8_t *ptr = &singleSounds[(e-AU_INACTIVITY)<<2];
231 uint8_t tFreq = pgm_read_byte(ptr++);
232 uint8_t tLen = pgm_read_byte(ptr++);
233 uint8_t tPause = pgm_read_byte(ptr++);
234 uint8_t tFlags = pgm_read_byte(ptr);
235 play(tFreq, tLen, tPause, tFlags);
236 break;
243 void audioDefevent(uint8_t e)
245 audio.event(e);
248 void audioKeyPress()
250 #if defined(AUDIO)
251 if (g_eeGeneral.beepMode == e_mode_all) {
252 audio.play(BEEP_DEFAULT_FREQ, 10, 1, PLAY_NOW);
254 #else
255 beep(0);
256 #endif
258 #if defined(HAPTIC)
259 if (g_eeGeneral.hapticMode == e_mode_all) {
260 haptic.play(5, 0, PLAY_NOW);
262 #endif
265 void audioTrimPress(int16_t value)
267 if (g_eeGeneral.beepMode >= e_mode_nokeys) {
268 #if defined(AUDIO)
269 value = limit<int16_t>(TRIM_MIN, value, TRIM_MAX);
270 value >>= 2;
271 value += 60;
272 audio.play(value, 6, 1, PLAY_NOW);
273 #else
274 warble = true;
275 beep(1);
276 #endif
280 void audioTimerCountdown(uint8_t timer, int value)
282 if (0) {
283 // pass
286 #if defined(CPUM2560) && (defined(VOICE_WTV20) || defined(VOICE_JQ6500))
287 else if (g_model.timers[timer].countdownBeep == COUNTDOWN_VOICE) {
288 if (value >= 0 && value <= TIMER_COUNTDOWN_START(timer)) {
289 playNumber(value, 0, 0);
291 else if (value == 30 || value == 20) {
292 playDuration(value);
295 #endif
297 #if defined(HAPTIC)
298 else if (g_model.timers[timer].countdownBeep == COUNTDOWN_HAPTIC) {
299 if (value == 0) {
300 haptic.play(15, 3, PLAY_NOW);
302 else if (value > 0 && value <= 10) {
303 haptic.play(5, 0, PLAY_NOW);
305 else if (value == 30) {
306 haptic.play(10, 3, PLAY_REPEAT(2) | PLAY_NOW);
308 else if (value == 20) {
309 haptic.play(10, 3, PLAY_REPEAT(1) | PLAY_NOW);
312 #endif
314 else {
315 if (value == 0) {
316 audio.play(BEEP_DEFAULT_FREQ + 50, 30, 3, PLAY_NOW);
318 else if (value > 0 && value <= 10) {
319 audio.play(BEEP_DEFAULT_FREQ + 50, 15, 3, PLAY_NOW);
321 else if (value == 30) {
322 audio.play(BEEP_DEFAULT_FREQ + 50, 15, 3, PLAY_REPEAT(2) | PLAY_NOW);
324 else if (value == 20) {
325 audio.play(BEEP_DEFAULT_FREQ + 50, 15, 3, PLAY_REPEAT(1) | PLAY_NOW);