Translate last missing field + correct some translation (confirmation box) when delet...
[opentx.git] / radio / src / audio_arm.h
blob1e244dac321deef834508291ad51f767280a9112
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 #ifndef _AUDIO_ARM_H_
22 #define _AUDIO_ARM_H_
24 #include <stddef.h>
25 #include "ff.h"
28 Implements a bit field, number of bits is set by the template,
29 each bit can be modified and read by the provided methods.
31 template <unsigned int NUM_BITS> class BitField {
32 private:
33 uint8_t bits[(NUM_BITS+7)/8];
34 public:
35 BitField()
37 reset();
40 void reset()
42 memset(bits, 0, sizeof(bits));
45 void setBit(unsigned int bitNo)
47 if (bitNo >= NUM_BITS) return;
48 bits[bitNo >> 3] = bits[bitNo >> 3] | (1 << (bitNo & 0x07));
51 bool getBit(unsigned int bitNo) const
53 // assert(bitNo < NUM_BITS);
54 if (bitNo >= NUM_BITS) return false;
55 return bits[bitNo >> 3] & (1 << (bitNo & 0x07));
58 unsigned int getSize() const
60 return NUM_BITS;
64 #define INDEX_LOGICAL_SWITCH_AUDIO_FILE(index, event) (2*(index)+(event))
65 #define INDEX_PHASE_AUDIO_FILE(index, event) (2*(index)+(event))
68 #define AUDIO_FILENAME_MAXLEN (42) // max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav)
69 #define AUDIO_QUEUE_LENGTH (16) // must be a power of 2!
71 #define AUDIO_SAMPLE_RATE (32000)
72 #define AUDIO_BUFFER_DURATION (10)
73 #define AUDIO_BUFFER_SIZE (AUDIO_SAMPLE_RATE*AUDIO_BUFFER_DURATION/1000)
75 #if defined(SIMU) && defined(SIMU_AUDIO)
76 #define AUDIO_BUFFER_COUNT (10) // simulator needs more buffers for smooth audio
77 #elif defined(PCBX12S)
78 #define AUDIO_BUFFER_COUNT (2) // smaller than Taranis since there is also a buffer on the ADC chip
79 #else
80 #define AUDIO_BUFFER_COUNT (3)
81 #endif
83 #define BEEP_MIN_FREQ (150)
84 #define BEEP_MAX_FREQ (15000)
85 #define BEEP_DEFAULT_FREQ (2250)
86 #define BEEP_KEY_UP_FREQ (BEEP_DEFAULT_FREQ+150)
87 #define BEEP_KEY_DOWN_FREQ (BEEP_DEFAULT_FREQ-150)
89 #if defined(AUDIO_DUAL_BUFFER)
90 enum AudioBufferState
92 AUDIO_BUFFER_FREE,
93 AUDIO_BUFFER_FILLED,
94 AUDIO_BUFFER_PLAYING
96 #endif
98 #if defined(SIMU)
99 typedef uint16_t audio_data_t;
100 #define AUDIO_DATA_SILENCE 0x8000
101 #define AUDIO_DATA_MIN 0
102 #define AUDIO_DATA_MAX 0xffff
103 #define AUDIO_BITS_PER_SAMPLE 16
104 #elif defined(PCBX12S)
105 typedef int16_t audio_data_t;
106 #define AUDIO_DATA_SILENCE 0
107 #define AUDIO_DATA_MIN INT16_MIN
108 #define AUDIO_DATA_MAX INT16_MAX
109 #define AUDIO_BITS_PER_SAMPLE 16
110 #else
111 typedef uint16_t audio_data_t;
112 #define AUDIO_DATA_SILENCE (0x8000 >> 4)
113 #define AUDIO_DATA_MIN 0
114 #define AUDIO_DATA_MAX 0x0fff
115 #define AUDIO_BITS_PER_SAMPLE 12
116 #endif
118 struct AudioBuffer {
119 audio_data_t data[AUDIO_BUFFER_SIZE];
120 uint16_t size;
121 #if defined(AUDIO_DUAL_BUFFER)
122 uint8_t state;
123 #endif
126 extern AudioBuffer audioBuffers[AUDIO_BUFFER_COUNT];
128 enum FragmentTypes {
129 FRAGMENT_EMPTY,
130 FRAGMENT_TONE,
131 FRAGMENT_FILE,
134 struct Tone {
135 uint16_t freq;
136 uint16_t duration;
137 uint16_t pause;
138 int8_t freqIncr;
139 uint8_t reset;
140 Tone() {};
141 Tone(uint16_t freq, uint16_t duration, uint16_t pause, int8_t freqIncr, bool reset):
142 freq(freq),
143 duration(duration),
144 pause(pause),
145 freqIncr(freqIncr),
146 reset(reset)
151 struct AudioFragment {
152 uint8_t type;
153 uint8_t id;
154 uint8_t repeat;
155 union {
156 Tone tone;
157 char file[AUDIO_FILENAME_MAXLEN+1];
160 AudioFragment() { clear(); };
162 AudioFragment(uint16_t freq, uint16_t duration, uint16_t pause, uint8_t repeat, int8_t freqIncr, bool reset, uint8_t id=0):
163 type(FRAGMENT_TONE),
164 id(id),
165 repeat(repeat),
166 tone(freq, duration, pause, freqIncr, reset)
169 AudioFragment(const char * filename, uint8_t repeat, uint8_t id=0):
170 type(FRAGMENT_FILE),
171 id(id),
172 repeat(repeat)
174 strcpy(file, filename);
177 void clear() { memset(this, 0, sizeof(AudioFragment)); };
180 class ToneContext {
181 public:
183 inline void clear() { memset(this, 0, sizeof(ToneContext)); };
184 bool isFree() const { return fragment.type == FRAGMENT_EMPTY; };
185 int mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade);
187 void setFragment(uint16_t freq, uint16_t duration, uint16_t pause, uint8_t repeat, int8_t freqIncr, bool reset, uint8_t id=0)
189 fragment = AudioFragment(freq, duration, pause, repeat, freqIncr, reset, id);
192 private:
193 AudioFragment fragment;
195 struct {
196 float step;
197 float idx;
198 float volume;
199 uint16_t freq;
200 uint16_t duration;
201 uint16_t pause;
202 } state;
206 class WavContext {
207 public:
209 inline void clear() { fragment.clear(); };
211 int mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade);
212 bool hasId(uint8_t id) const { return fragment.id == id; };
214 void setFragment(const char * filename, uint8_t repeat, uint8_t id)
216 fragment = AudioFragment(filename, repeat, id);
219 void stop(uint8_t id)
221 if (fragment.id == id) {
222 fragment.clear();
226 private:
227 AudioFragment fragment;
229 struct {
230 FIL file;
231 uint8_t codec;
232 uint32_t freq;
233 uint32_t size;
234 uint8_t resampleRatio;
235 uint16_t readSize;
236 } state;
239 class MixedContext {
240 #if defined(CLI)
241 friend void printAudioVars();
242 #endif
243 public:
245 MixedContext()
247 clear();
250 void setFragment(const AudioFragment * frag)
252 if (frag) {
253 fragment = *frag;
257 inline void clear()
259 tone.clear(); // the biggest member of the uninon
262 bool isEmpty() const { return fragment.type == FRAGMENT_EMPTY; };
263 bool isTone() const { return fragment.type == FRAGMENT_TONE; };
264 bool isFile() const { return fragment.type == FRAGMENT_FILE; };
265 bool hasId(uint8_t id) const { return fragment.id == id; };
267 int mixBuffer(AudioBuffer *buffer, int toneVolume, int wavVolume, unsigned int fade)
269 if (isTone()) return tone.mixBuffer(buffer, toneVolume, fade);
270 else if (isFile()) return wav.mixBuffer(buffer, wavVolume, fade);
271 return 0;
274 private:
275 union {
276 AudioFragment fragment; // a hack: fragment is used to access the fragment members of tone and wav
277 ToneContext tone;
278 WavContext wav;
283 class AudioBufferFifo {
284 #if defined(CLI)
285 friend void printAudioVars();
286 #endif
288 private:
289 volatile uint8_t readIdx;
290 volatile uint8_t writeIdx;
291 volatile bool bufferFull;
293 // readIdx == writeIdx -> buffer empty
294 // readIdx == writeIdx + 1 -> buffer full
296 inline uint8_t nextBufferIdx(uint8_t idx) const
298 return (idx >= AUDIO_BUFFER_COUNT-1 ? 0 : idx+1);
300 bool full() const
302 return bufferFull;
304 bool empty() const
306 return (readIdx == writeIdx) && !bufferFull;
308 uint8_t used() const
310 return bufferFull ? AUDIO_BUFFER_COUNT : writeIdx - readIdx;
313 public:
314 AudioBufferFifo() : readIdx(0), writeIdx(0), bufferFull(false)
316 memset(audioBuffers, 0, sizeof(audioBuffers));
319 // returns an empty buffer to be filled wit data and put back into FIFO with audioPushBuffer()
320 AudioBuffer * getEmptyBuffer() const
322 #if defined(AUDIO_DUAL_BUFFER)
323 AudioBuffer * buffer = &audioBuffers[writeIdx];
324 return buffer->state == AUDIO_BUFFER_FREE ? buffer : NULL;
325 #else
326 return full() ? NULL : &audioBuffers[writeIdx];
327 #endif
330 // puts filled buffer into FIFO
331 void audioPushBuffer()
333 audioDisableIrq();
334 #if defined(AUDIO_DUAL_BUFFER)
335 AudioBuffer * buffer = &audioBuffers[writeIdx];
336 buffer->state = AUDIO_BUFFER_FILLED;
337 #endif
338 writeIdx = nextBufferIdx(writeIdx);
339 bufferFull = (writeIdx == readIdx);
340 audioEnableIrq();
343 // returns a pointer to the audio buffer to be played
344 const AudioBuffer * getNextFilledBuffer()
346 #if defined(AUDIO_DUAL_BUFFER)
347 uint8_t idx = readIdx;
348 do {
349 AudioBuffer * buffer = &audioBuffers[idx];
350 if (buffer->state == AUDIO_BUFFER_FILLED) {
351 buffer->state = AUDIO_BUFFER_PLAYING;
352 readIdx = idx;
353 return buffer;
355 idx = nextBufferIdx(idx);
356 } while (idx != writeIdx); // this fixes a bug if all buffers are filled
357 return NULL;
358 #else
359 return empty() ? NULL : &audioBuffers[readIdx];
360 #endif
363 // frees the last played buffer
364 void freeNextFilledBuffer()
366 audioDisableIrq();
367 #if defined(AUDIO_DUAL_BUFFER)
368 if (audioBuffers[readIdx].state == AUDIO_BUFFER_PLAYING) {
369 audioBuffers[readIdx].state = AUDIO_BUFFER_FREE;
370 readIdx = nextBufferIdx(readIdx);
371 bufferFull = false;
373 #else
374 readIdx = nextBufferIdx(readIdx);
375 bufferFull = false;
376 #endif
377 audioEnableIrq();
380 bool filledAtleast(int noBuffers) const
382 #if defined(AUDIO_DUAL_BUFFER)
383 int count = 0;
384 for(int n= 0; n<AUDIO_BUFFER_COUNT; ++n) {
385 if (audioBuffers[n].state == AUDIO_BUFFER_FILLED) {
386 if (++count >= noBuffers) {
387 return true;
391 return false;
392 #else
393 return used() >= noBuffers;
394 #endif
399 class AudioFragmentFifo
401 #if defined(CLI)
402 friend void printAudioVars();
403 #endif
404 private:
405 volatile uint8_t ridx;
406 volatile uint8_t widx;
407 AudioFragment fragments[AUDIO_QUEUE_LENGTH];
409 uint8_t nextIdx(uint8_t idx) const
411 return (idx + 1) & (AUDIO_QUEUE_LENGTH - 1);
414 public:
415 AudioFragmentFifo() : ridx(0), widx(0), fragments() {};
417 bool hasId(uint8_t id)
419 uint8_t i = ridx;
420 while (i != widx) {
421 AudioFragment & fragment = fragments[i];
422 if (fragment.id == id) return true;
423 i = nextIdx(i);
425 return false;
428 bool empty() const
430 return ridx == widx;
433 bool full() const
435 return ridx == nextIdx(widx);
438 void clear()
440 widx = ridx; // clean the queue
443 const AudioFragment * get()
445 if (!empty()) {
446 const AudioFragment * result = &fragments[ridx];
447 if (!fragments[ridx].repeat--) {
448 // repeat is done, move to the next fragment
449 ridx = nextIdx(ridx);
451 return result;
453 return 0;
456 void push(const AudioFragment & fragment)
458 if (!full()) {
459 // TRACE("fragment %d at %d", fragment.type, widx);
460 fragments[widx] = fragment;
461 widx = nextIdx(widx);
467 class AudioQueue {
469 #if defined(SIMU_AUDIO)
470 friend void fillAudioBuffer(void *, uint8_t *, int);
471 #endif
472 #if defined(CLI)
473 friend void printAudioVars();
474 #endif
475 public:
476 AudioQueue();
477 void start() { _started = true; };
478 void playTone(uint16_t freq, uint16_t len, uint16_t pause=0, uint8_t flags=0, int8_t freqIncr=0);
479 void playFile(const char *filename, uint8_t flags=0, uint8_t id=0);
480 void stopPlay(uint8_t id);
481 void stopAll();
482 void flush();
483 void pause(uint16_t tLen);
484 void stopSD();
485 bool isPlaying(uint8_t id);
486 bool isEmpty() const { return fragmentsFifo.empty(); };
487 void wakeup();
488 bool started() const { return _started; };
490 AudioBufferFifo buffersFifo;
492 private:
493 volatile bool _started;
494 MixedContext normalContext;
495 WavContext backgroundContext;
496 ToneContext priorityContext;
497 ToneContext varioContext;
498 AudioFragmentFifo fragmentsFifo;
501 extern uint8_t currentSpeakerVolume;
502 extern AudioQueue audioQueue;
504 enum {
505 ID_PLAY_FROM_SD_MANAGER = 254,
506 ID_PLAY_BYE = 255
509 void codecsInit();
510 void audioEvent(unsigned int index);
511 void audioPlay(unsigned int index, uint8_t id=0);
512 void audioStart();
514 #if defined(AUDIO) && defined(BUZZER)
515 #define AUDIO_BUZZER(a, b) do { a; b; } while(0)
516 #elif defined(AUDIO)
517 #define AUDIO_BUZZER(a, b) a
518 #else
519 #define AUDIO_BUZZER(a, b) b
520 #endif
522 #if defined(VOICE)
523 #define AUDIO_ERROR_MESSAGE(e) audioEvent(e)
524 #define AUDIO_TIMER_MINUTE(t) playDuration(t, 0, 0)
525 #else
526 #define AUDIO_ERROR_MESSAGE(e) audioEvent(AU_ERROR)
527 #define AUDIO_TIMER_MINUTE(t) audioDefevent(AU_WARNING1)
528 #endif
530 void audioKeyPress();
531 void audioKeyError();
532 void audioTrimPress(int value);
533 void audioTimerCountdown(uint8_t timer, int value);
535 #define AUDIO_KEY_PRESS() audioKeyPress()
536 #define AUDIO_KEY_ERROR() audioKeyError()
538 #define AUDIO_HELLO() audioPlay(AUDIO_HELLO)
539 #define AUDIO_BYE() audioPlay(AU_BYE, ID_PLAY_BYE)
540 #define AUDIO_WARNING1() AUDIO_BUZZER(audioEvent(AU_WARNING1), beep(3))
541 #define AUDIO_WARNING2() AUDIO_BUZZER(audioEvent(AU_WARNING2), beep(2))
542 #define AUDIO_TX_BATTERY_LOW() AUDIO_BUZZER(audioEvent(AU_TX_BATTERY_LOW), beep(4))
543 #if defined(PCBSKY9X)
544 #define AUDIO_TX_MAH_HIGH() audioEvent(AU_TX_MAH_HIGH)
545 #define AUDIO_TX_TEMP_HIGH() audioEvent(AU_TX_TEMP_HIGH)
546 #endif
547 #define AUDIO_ERROR() AUDIO_BUZZER(audioEvent(AU_ERROR), beep(4))
548 #define AUDIO_TIMER_COUNTDOWN(idx, val) audioTimerCountdown(idx, val)
549 #define AUDIO_TIMER_ELAPSED(idx) AUDIO_BUZZER(audioEvent(AU_TIMER1_ELAPSED+idx), beep(3))
550 #define AUDIO_INACTIVITY() AUDIO_BUZZER(audioEvent(AU_INACTIVITY), beep(3))
551 #define AUDIO_MIX_WARNING(x) AUDIO_BUZZER(audioEvent(AU_MIX_WARNING_1+x-1), beep(1))
552 #define AUDIO_POT_MIDDLE(x) AUDIO_BUZZER(audioEvent(AU_STICK1_MIDDLE+x), beep(2))
553 #define AUDIO_TRIM_MIDDLE() AUDIO_BUZZER(audioEvent(AU_TRIM_MIDDLE), beep(2))
554 #define AUDIO_TRIM_MIN() AUDIO_BUZZER(audioEvent(AU_TRIM_MIN), beep(2))
555 #define AUDIO_TRIM_MAX() AUDIO_BUZZER(audioEvent(AU_TRIM_MAX), beep(2))
556 #define AUDIO_TRIM_PRESS(val) audioTrimPress(val)
557 #define AUDIO_PLAY(p) audioEvent(p)
558 #define AUDIO_VARIO(fq, t, p, f) audioQueue.playTone(fq, t, p, f)
559 #define AUDIO_RSSI_ORANGE() audioEvent(AU_RSSI_ORANGE)
560 #define AUDIO_RSSI_RED() audioEvent(AU_RSSI_RED)
561 #define AUDIO_SWR_RED() audioEvent(AU_SWR_RED)
562 #define AUDIO_TELEMETRY_LOST() audioEvent(AU_TELEMETRY_LOST)
563 #define AUDIO_TELEMETRY_BACK() audioEvent(AU_TELEMETRY_BACK)
564 #define AUDIO_TRAINER_LOST() audioEvent(AU_TRAINER_LOST)
565 #define AUDIO_TRAINER_BACK() audioEvent(AU_TRAINER_BACK)
567 #define AUDIO_HEARTBEAT()
569 enum AutomaticPromptsCategories {
570 SYSTEM_AUDIO_CATEGORY,
571 MODEL_AUDIO_CATEGORY,
572 PHASE_AUDIO_CATEGORY,
573 SWITCH_AUDIO_CATEGORY,
574 LOGICAL_SWITCH_AUDIO_CATEGORY,
577 enum AutomaticPromptsEvents {
578 AUDIO_EVENT_OFF,
579 AUDIO_EVENT_ON,
580 AUDIO_EVENT_MID,
583 void pushPrompt(uint16_t prompt, uint8_t id=0);
584 void pushUnit(uint8_t unit, uint8_t idx, uint8_t id);
585 void playModelName();
587 #define I18N_PLAY_FUNCTION(lng, x, ...) void lng ## _ ## x(__VA_ARGS__, uint8_t id)
588 #define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__, uint8_t id)
589 #define PUSH_NUMBER_PROMPT(p) pushPrompt((p), id)
590 #define PUSH_UNIT_PROMPT(p, i) pushUnit((p), (i), id)
591 #define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a), id)
592 #define PLAY_DURATION(d, att) playDuration((d), (att), id)
593 #define PLAY_DURATION_ATT , uint8_t flags
594 #define PLAY_TIME 1
595 #define IS_PLAY_TIME() (flags&PLAY_TIME)
596 #define IS_PLAYING(id) audioQueue.isPlaying((id))
597 #define PLAY_VALUE(v, id) playValue((v), (id))
598 #define PLAY_FILE(f, flags, id) audioQueue.playFile((f), (flags), (id))
599 #define STOP_PLAY(id) audioQueue.stopPlay((id))
600 #define AUDIO_RESET() audioQueue.stopAll()
601 #define AUDIO_FLUSH() audioQueue.flush()
603 #if defined(SDCARD)
604 extern tmr10ms_t timeAutomaticPromptsSilence;
605 void playModelEvent(uint8_t category, uint8_t index, event_t event=0);
606 #define PLAY_PHASE_OFF(phase) playModelEvent(PHASE_AUDIO_CATEGORY, phase, AUDIO_EVENT_OFF)
607 #define PLAY_PHASE_ON(phase) playModelEvent(PHASE_AUDIO_CATEGORY, phase, AUDIO_EVENT_ON)
608 #define PLAY_SWITCH_MOVED(sw) playModelEvent(SWITCH_AUDIO_CATEGORY, sw)
609 #define PLAY_LOGICAL_SWITCH_OFF(sw) playModelEvent(LOGICAL_SWITCH_AUDIO_CATEGORY, sw, AUDIO_EVENT_OFF)
610 #define PLAY_LOGICAL_SWITCH_ON(sw) playModelEvent(LOGICAL_SWITCH_AUDIO_CATEGORY, sw, AUDIO_EVENT_ON)
611 #define PLAY_MODEL_NAME() playModelName()
612 #define START_SILENCE_PERIOD() timeAutomaticPromptsSilence = get_tmr10ms()
613 #define IS_SILENCE_PERIOD_ELAPSED() (get_tmr10ms()-timeAutomaticPromptsSilence > 50)
614 #else
615 #define PLAY_PHASE_OFF(phase)
616 #define PLAY_PHASE_ON(phase)
617 #define PLAY_SWITCH_MOVED(sw)
618 #define PLAY_LOGICAL_SWITCH_OFF(sw)
619 #define PLAY_LOGICAL_SWITCH_ON(sw)
620 #define PLAY_MODEL_NAME()
621 #define START_SILENCE_PERIOD()
622 #endif
624 char * getAudioPath(char * path);
626 void referenceSystemAudioFiles();
627 void referenceModelAudioFiles();
629 bool isAudioFileReferenced(uint32_t i, char * filename/*at least AUDIO_FILENAME_MAXLEN+1 long*/);
631 #endif // _AUDIO_ARM_H_