Skip to content

Commit

Permalink
feat(lua): Add API for overriding speaker volume (#3784)
Browse files Browse the repository at this point in the history
  • Loading branch information
mha1 authored Oct 13, 2023
1 parent ff2b3ac commit 7400a59
Show file tree
Hide file tree
Showing 22 changed files with 157 additions and 67 deletions.
30 changes: 18 additions & 12 deletions radio/src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,9 @@ int WavContext::mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade)
FRESULT result = FR_OK;
UINT read = 0;

if(fragment.fragmentVolume != USE_SETTINGS_VOLUME)
volume = fragment.fragmentVolume;

if (fragment.file[1]) {
result = f_open(&state.file, fragment.file, FA_OPEN_EXISTING | FA_READ);
fragment.file[1] = 0;
Expand Down Expand Up @@ -652,6 +655,9 @@ int ToneContext::mixBuffer(AudioBuffer * buffer, int volume, unsigned int fade)
int duration = 0;
int result = 0;

if(fragment.fragmentVolume != USE_SETTINGS_VOLUME)
volume = fragment.fragmentVolume;

int remainingDuration = fragment.tone.duration - state.duration;
if (remainingDuration > 0) {
int points;
Expand Down Expand Up @@ -837,7 +843,7 @@ bool AudioQueue::isPlaying(uint8_t id)
fragmentsFifo.hasPromptId(id);
}

void AudioQueue::playTone(uint16_t freq, uint16_t len, uint16_t pause, uint8_t flags, int8_t freqIncr)
void AudioQueue::playTone(uint16_t freq, uint16_t len, uint16_t pause, uint8_t flags, int8_t freqIncr, int8_t fragmentVolume)
{
#if defined(SIMU) && !defined(SIMU_AUDIO)
return;
Expand All @@ -848,7 +854,7 @@ void AudioQueue::playTone(uint16_t freq, uint16_t len, uint16_t pause, uint8_t f
freq = limit<uint16_t>(BEEP_MIN_FREQ, freq, BEEP_MAX_FREQ);

if (flags & PLAY_BACKGROUND) {
varioContext.setFragment(freq, len, pause, 0, 0, (flags & PLAY_NOW));
varioContext.setFragment(freq, len, pause, 0, 0, (flags & PLAY_NOW), fragmentVolume);
}
else {
// adjust frequency and length according to the user preferences
Expand All @@ -858,22 +864,22 @@ void AudioQueue::playTone(uint16_t freq, uint16_t len, uint16_t pause, uint8_t f
if (flags & PLAY_NOW) {
if (priorityContext.isFree()) {
priorityContext.clear();
priorityContext.setFragment(freq, len, pause, flags & 0x0f, freqIncr, false);
priorityContext.setFragment(freq, len, pause, flags & 0x0f, freqIncr, false, fragmentVolume);
}
}
else {
fragmentsFifo.push(AudioFragment(freq, len, pause, flags & 0x0f, freqIncr, false));
fragmentsFifo.push(AudioFragment(freq, len, pause, flags & 0x0f, freqIncr, false, fragmentVolume));
}
}

RTOS_UNLOCK_MUTEX(audioMutex);
}

#if defined(SDCARD)
void AudioQueue::playFile(const char * filename, uint8_t flags, uint8_t id)
void AudioQueue::playFile(const char * filename, uint8_t flags, uint8_t id, int8_t fragmentVolume)
{
#if defined(SIMU)
TRACE("playFile(\"%s\", flags=%x, id=%d)", filename, flags, id);
TRACE("playFile(\"%s\", flags=%x, id=%d fragmentVolume=%d ee_general=%d)", filename, flags, id, fragmentVolume, g_eeGeneral.wavVolume);
if (strlen(filename) > AUDIO_FILENAME_MAXLEN) {
TRACE("file name too long! maximum length is %d characters", AUDIO_FILENAME_MAXLEN);
return;
Expand All @@ -898,10 +904,10 @@ void AudioQueue::playFile(const char * filename, uint8_t flags, uint8_t id)

if (flags & PLAY_BACKGROUND) {
backgroundContext.clear();
backgroundContext.setFragment(filename, 0, id);
backgroundContext.setFragment(filename, 0, fragmentVolume, id);
}
else {
fragmentsFifo.push(AudioFragment(filename, flags & 0x0f, id));
fragmentsFifo.push(AudioFragment(filename, flags & 0x0f, fragmentVolume, id));
}

RTOS_UNLOCK_MUTEX(audioMutex);
Expand Down Expand Up @@ -1223,22 +1229,22 @@ void audioEvent(unsigned int index)
}

#if defined(SDCARD)
void pushUnit(uint8_t unit, uint8_t idx, uint8_t id)
void pushUnit(uint8_t unit, uint8_t idx, uint8_t id, uint8_t fragmentVolume)
{
if (unit < DIM(unitsFilenames)) {
char path[AUDIO_FILENAME_MAXLEN+1];
char * tmp = strAppendSystemAudioPath(path);
tmp = strAppendStringWithIndex(tmp, unitsFilenames[unit], idx);
strcpy(tmp, SOUNDS_EXT);
audioQueue.playFile(path, 0, id);
audioQueue.playFile(path, 0, id, fragmentVolume);
}
else {
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.
}
}
#endif

void pushPrompt(uint16_t prompt, uint8_t id)
void pushPrompt(uint16_t prompt, uint8_t id, uint8_t fragmentVolume)
{
#if defined(SDCARD)
char filename[AUDIO_FILENAME_MAXLEN+1];
Expand All @@ -1248,7 +1254,7 @@ void pushPrompt(uint16_t prompt, uint8_t id)
str[i] = '0' + (prompt%10);
prompt /= 10;
}
audioQueue.playFile(filename, 0, id);
audioQueue.playFile(filename, 0, id, fragmentVolume);
#endif
}

Expand Down
46 changes: 27 additions & 19 deletions radio/src/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MOD
#define BEEP_MAX_FREQ (15000)
#define BEEP_DEFAULT_FREQ (2250)

#define USE_SETTINGS_VOLUME (127)

#if defined(AUDIO_DUAL_BUFFER)
enum AudioBufferState
{
Expand Down Expand Up @@ -156,31 +158,36 @@ struct AudioFragment {
uint8_t type;
uint8_t id;
uint8_t repeat;
int8_t fragmentVolume;
union {
Tone tone;
char file[AUDIO_FILENAME_MAXLEN+1];
};

AudioFragment() { clear(); };

AudioFragment(uint16_t freq, uint16_t duration, uint16_t pause, uint8_t repeat, int8_t freqIncr, bool reset, uint8_t id=0):
AudioFragment(uint16_t freq, uint16_t duration, uint16_t pause, uint8_t repeat, int8_t freqIncr, bool reset, int8_t fragmentVolume, uint8_t id=0 ):
type(FRAGMENT_TONE),
id(id),
repeat(repeat),
fragmentVolume(fragmentVolume),
tone(freq, duration, pause, freqIncr, reset)
{};

AudioFragment(const char * filename, uint8_t repeat, uint8_t id=0):
AudioFragment(const char * filename, uint8_t repeat, int8_t fragmentVolume, uint8_t id = 0):
type(FRAGMENT_FILE),
id(id),
repeat(repeat)
repeat(repeat),
fragmentVolume(fragmentVolume)
{
strcpy(file, filename);
}

void clear()
{
memset(reinterpret_cast<void*>(this), 0, sizeof(AudioFragment));

this->fragmentVolume = USE_SETTINGS_VOLUME;
}
};

Expand All @@ -190,6 +197,8 @@ class ToneContext {
inline void clear()
{
memset(reinterpret_cast<void*>(this), 0, sizeof(ToneContext));

fragment.fragmentVolume = USE_SETTINGS_VOLUME;
}

bool isFree() const
Expand All @@ -199,9 +208,9 @@ class ToneContext {

int mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade);

void setFragment(uint16_t freq, uint16_t duration, uint16_t pause, uint8_t repeat, int8_t freqIncr, bool reset, uint8_t id=0)
void setFragment(uint16_t freq, uint16_t duration, uint16_t pause, uint8_t repeat, int8_t freqIncr, bool reset, int8_t fragmentVolume, uint8_t id = 0)
{
fragment = AudioFragment(freq, duration, pause, repeat, freqIncr, reset, id);
fragment = AudioFragment(freq, duration, pause, repeat, freqIncr, reset, fragmentVolume, id);
}

private:
Expand All @@ -226,9 +235,9 @@ class WavContext {
int mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade);
bool hasPromptId(uint8_t id) const { return fragment.id == id; };

void setFragment(const char * filename, uint8_t repeat, uint8_t id)
void setFragment(const char * filename, uint8_t repeat, int8_t fragmentVolume, uint8_t id)
{
fragment = AudioFragment(filename, repeat, id);
fragment = AudioFragment(filename, repeat, id, fragmentVolume);
}

void stop(uint8_t id)
Expand Down Expand Up @@ -294,7 +303,6 @@ class MixedContext {
ToneContext tone;
WavContext wav;
};

};

class AudioBufferFifo {
Expand Down Expand Up @@ -506,8 +514,8 @@ class AudioQueue {
public:
AudioQueue();
void start() { _started = true; };
void playTone(uint16_t freq, uint16_t len, uint16_t pause=0, uint8_t flags=0, int8_t freqIncr=0);
void playFile(const char *filename, uint8_t flags=0, uint8_t id=0);
void playTone(uint16_t freq, uint16_t len, uint16_t pause=0, uint8_t flags=0, int8_t freqIncr=0, int8_t fragmentVolume = USE_SETTINGS_VOLUME);
void playFile(const char *filename, uint8_t flags=0, uint8_t id=0, int8_t fragmentVolume = USE_SETTINGS_VOLUME);
void stopPlay(uint8_t id);
void stopAll();
void flush();
Expand Down Expand Up @@ -609,24 +617,24 @@ enum AutomaticPromptsEvents {
AUDIO_EVENT_MID,
};

void pushPrompt(uint16_t prompt, uint8_t id=0);
void pushUnit(uint8_t unit, uint8_t idx, uint8_t id);
void pushPrompt(uint16_t prompt, uint8_t id=0, uint8_t fragmentVolume = USE_SETTINGS_VOLUME);
void pushUnit(uint8_t unit, uint8_t idx, uint8_t id, uint8_t fragmentVolume = USE_SETTINGS_VOLUME);
void playModelName();

#define I18N_PLAY_FUNCTION(lng, x, ...) void lng ## _ ## x(__VA_ARGS__, uint8_t id)
#define PUSH_NUMBER_PROMPT(p) pushPrompt((p), id)
#define PUSH_UNIT_PROMPT(p, i) pushUnit((p), (i), id)
#define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a), id)
#define PLAY_DURATION(d, att) playDuration((d), (att), id)
#define I18N_PLAY_FUNCTION(lng, x, ...) void lng ## _ ## x(__VA_ARGS__, uint8_t id, int8_t fragmentVolume = USE_SETTINGS_VOLUME)
#define PUSH_NUMBER_PROMPT(p) pushPrompt((p), id, fragmentVolume)
#define PUSH_UNIT_PROMPT(p, i) pushUnit((p), (i), id, fragmentVolume)
#define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a), id, fragmentVolume)
#define PLAY_DURATION(d, att) playDuration((d), (att), id, fragmentVolume)
#define PLAY_DURATION_ATT , uint8_t flags
#define PLAY_TIME 1
#define PLAY_LONG_TIMER 2
#define LONG_TIMER_DURATION (10 * 60) // 10 minutes
#define IS_PLAY_TIME() (flags & PLAY_TIME)
#define IS_PLAY_LONG_TIMER() (flags & PLAY_LONG_TIMER)
#define IS_PLAYING(id) audioQueue.isPlaying((id))
#define PLAY_VALUE(v, id) playValue((v), (id))
#define PLAY_FILE(f, flags, id) audioQueue.playFile((f), (flags), (id))
#define PLAY_VALUE(v, id) playValue((v), (id), USE_SETTINGS_VOLUME)
#define PLAY_FILE(f, flags, id) audioQueue.playFile((f), (flags), (id), USE_SETTINGS_VOLUME)
#define STOP_PLAY(id) audioQueue.stopPlay((id))
#define AUDIO_RESET() audioQueue.stopAll()
#define AUDIO_FLUSH() audioQueue.flush()
Expand Down
Loading

0 comments on commit 7400a59

Please sign in to comment.