Skip to content
This repository has been archived by the owner on Jul 28, 2024. It is now read-only.

Commit

Permalink
Merge pull request #9 from xMasterX/redbox_ca_fix
Browse files Browse the repository at this point in the history
Add Redbox (CA) to menu, apply ./fbt format
  • Loading branch information
litui authored Nov 24, 2022
2 parents 6006c9f + fba220c commit 837ce09
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 213 deletions.
4 changes: 2 additions & 2 deletions dtmf_dolphin.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ static void app_free(DTMFDolphinApp* app) {
free(app);
}

int32_t dtmf_dolphin_app(void *p) {
int32_t dtmf_dolphin_app(void* p) {
UNUSED(p);
DTMFDolphinApp* app = app_alloc();

view_dispatcher_run(app->view_dispatcher);

app_free(app);
Expand Down
92 changes: 49 additions & 43 deletions dtmf_dolphin_audio.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "dtmf_dolphin_audio.h"

DTMFDolphinAudio *current_player;
DTMFDolphinAudio* current_player;

static void dtmf_dolphin_audio_dma_isr(void* ctx) {
FuriMessageQueue *event_queue = ctx;
FuriMessageQueue* event_queue = ctx;

if (LL_DMA_IsActiveFlag_HT1(DMA1)) {
if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
LL_DMA_ClearFlag_HT1(DMA1);

DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAHalfTransfer};
Expand All @@ -21,13 +21,13 @@ static void dtmf_dolphin_audio_dma_isr(void* ctx) {
}

void dtmf_dolphin_audio_clear_samples(DTMFDolphinAudio* player) {
for (size_t i = 0; i < player->buffer_length; i++) {
for(size_t i = 0; i < player->buffer_length; i++) {
player->sample_buffer[i] = 0;
}
}

DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
DTMFDolphinOsc *osc = malloc(sizeof(DTMFDolphinOsc));
DTMFDolphinOsc* osc = malloc(sizeof(DTMFDolphinOsc));
osc->cached_freq = 0;
osc->offset = 0;
osc->period = 0;
Expand All @@ -36,7 +36,7 @@ DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
}

DTMFDolphinPulseFilter* dtmf_dolphin_pulse_filter_alloc() {
DTMFDolphinPulseFilter *pf = malloc(sizeof(DTMFDolphinPulseFilter));
DTMFDolphinPulseFilter* pf = malloc(sizeof(DTMFDolphinPulseFilter));
pf->duration = 0;
pf->period = 0;
pf->offset = 0;
Expand All @@ -45,7 +45,7 @@ DTMFDolphinPulseFilter* dtmf_dolphin_pulse_filter_alloc() {
}

DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
DTMFDolphinAudio *player = malloc(sizeof(DTMFDolphinAudio));
DTMFDolphinAudio* player = malloc(sizeof(DTMFDolphinAudio));
player->buffer_length = SAMPLE_BUFFER_LENGTH;
player->half_buffer_length = SAMPLE_BUFFER_LENGTH / 2;
player->sample_buffer = malloc(sizeof(uint16_t) * player->buffer_length);
Expand All @@ -61,64 +61,66 @@ DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
}

size_t calc_waveform_period(float freq) {
if (!freq) {
if(!freq) {
return 0;
}
// DMA Rate calculation, thanks to Dr_Zlo
float dma_rate = CPU_CLOCK_FREQ \
/ 2 \
/ DTMF_DOLPHIN_HAL_DMA_PRESCALER \
/ (DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
float dma_rate = CPU_CLOCK_FREQ / 2 / DTMF_DOLPHIN_HAL_DMA_PRESCALER /
(DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);

// Using a constant scaling modifier, which likely represents
// the combined system overhead and isr latency.
return (uint16_t) dma_rate * 2 / freq * 0.801923;
return (uint16_t)dma_rate * 2 / freq * 0.801923;
}

void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) {
if (osc->lookup_table != NULL) {
if(osc->lookup_table != NULL) {
free(osc->lookup_table);
}
osc->offset = 0;
osc->cached_freq = freq;
osc->period = calc_waveform_period(freq);
if (!osc->period) {
if(!osc->period) {
osc->lookup_table = NULL;
return;
}
osc->lookup_table = malloc(sizeof(float) * osc->period);

for (size_t i = 0; i < osc->period; i++) {
for(size_t i = 0; i < osc->period; i++) {
osc->lookup_table[i] = sin(i * PERIOD_2_PI / osc->period) + 1;
}
}

void filter_generate_lookup_table(DTMFDolphinPulseFilter* pf, uint16_t pulses, uint16_t pulse_ms, uint16_t gap_ms) {
if (pf->lookup_table != NULL) {
void filter_generate_lookup_table(
DTMFDolphinPulseFilter* pf,
uint16_t pulses,
uint16_t pulse_ms,
uint16_t gap_ms) {
if(pf->lookup_table != NULL) {
free(pf->lookup_table);
}
pf->offset = 0;

uint16_t gap_period = calc_waveform_period(1000 / (float) gap_ms);
uint16_t pulse_period = calc_waveform_period(1000 / (float) pulse_ms);
uint16_t gap_period = calc_waveform_period(1000 / (float)gap_ms);
uint16_t pulse_period = calc_waveform_period(1000 / (float)pulse_ms);
pf->period = pulse_period + gap_period;

if (!pf->period) {
if(!pf->period) {
pf->lookup_table = NULL;
return;
}
pf->duration = pf->period * pulses;
pf->lookup_table = malloc(sizeof(bool) * pf->duration);

for (size_t i = 0; i < pf->duration; i++) {
for(size_t i = 0; i < pf->duration; i++) {
pf->lookup_table[i] = i % pf->period < pulse_period;
}
}

float sample_frame(DTMFDolphinOsc* osc) {
float frame = 0.0;

if (osc->period) {
if(osc->period) {
frame = osc->lookup_table[osc->offset];
osc->offset = (osc->offset + 1) % osc->period;
}
Expand All @@ -129,8 +131,8 @@ float sample_frame(DTMFDolphinOsc* osc) {
bool sample_filter(DTMFDolphinPulseFilter* pf) {
bool frame = true;

if (pf->duration) {
if (pf->offset < pf->duration) {
if(pf->duration) {
if(pf->offset < pf->duration) {
frame = pf->lookup_table[pf->offset];
pf->offset = pf->offset + 1;
} else {
Expand All @@ -142,14 +144,14 @@ bool sample_filter(DTMFDolphinPulseFilter* pf) {
}

void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) {
if (osc->lookup_table != NULL) {
if(osc->lookup_table != NULL) {
free(osc->lookup_table);
}
free(osc);
}

void dtmf_dolphin_filter_free(DTMFDolphinPulseFilter* pf) {
if (pf->lookup_table != NULL) {
if(pf->lookup_table != NULL) {
free(pf->lookup_table);
}
free(pf);
Expand All @@ -165,22 +167,19 @@ void dtmf_dolphin_audio_free(DTMFDolphinAudio* player) {
current_player = NULL;
}


bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
uint16_t* sample_buffer_start = &player->sample_buffer[buffer_index];

for (size_t i = 0; i < player->half_buffer_length; i++) {
for(size_t i = 0; i < player->half_buffer_length; i++) {
float data = 0;
if (player->osc2->period) {
data = \
(sample_frame(player->osc1) / 2) + \
(sample_frame(player->osc2) / 2);
if(player->osc2->period) {
data = (sample_frame(player->osc1) / 2) + (sample_frame(player->osc2) / 2);
} else {
data = (sample_frame(player->osc1));
}
data *= sample_filter(player->filter) ? player->volume : 0.0;
data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned
data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned

if(data < 0) {
data = 0;
Expand All @@ -196,8 +195,13 @@ bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
return true;
}

bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, uint16_t pulse_ms, uint16_t gap_ms) {
if (current_player != NULL && current_player->playing) {
bool dtmf_dolphin_audio_play_tones(
float freq1,
float freq2,
uint16_t pulses,
uint16_t pulse_ms,
uint16_t gap_ms) {
if(current_player != NULL && current_player->playing) {
// Cannot start playing while still playing something else
return false;
}
Expand All @@ -213,7 +217,8 @@ bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, ui
dtmf_dolphin_speaker_init();
dtmf_dolphin_dma_init((uint32_t)current_player->sample_buffer, current_player->buffer_length);

furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);
furi_hal_interrupt_set_isr(
FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);

dtmf_dolphin_dma_start();
dtmf_dolphin_speaker_start();
Expand All @@ -222,11 +227,12 @@ bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, ui
}

bool dtmf_dolphin_audio_stop_tones() {
if (current_player != NULL && !current_player->playing) {
if(current_player != NULL && !current_player->playing) {
// Can't stop a player that isn't playing.
return false;
}
while(current_player->filter->offset > 0 && current_player->filter->offset < current_player->filter->duration) {
while(current_player->filter->offset > 0 &&
current_player->filter->offset < current_player->filter->duration) {
// run remaining ticks if needed to complete filter sequence
dtmf_dolphin_audio_handle_tick();
}
Expand All @@ -236,20 +242,20 @@ bool dtmf_dolphin_audio_stop_tones() {
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);

dtmf_dolphin_audio_free(current_player);

return true;
}

bool dtmf_dolphin_audio_handle_tick() {
bool handled = false;

if (current_player) {
if(current_player) {
DTMFDolphinCustomEvent event;
if(furi_message_queue_get(current_player->queue, &event, 250) == FuriStatusOk) {
if(event.type == DTMFDolphinEventDMAHalfTransfer) {
generate_waveform(current_player, 0);
handled = true;
} else if (event.type == DTMFDolphinEventDMAFullTransfer) {
} else if(event.type == DTMFDolphinEventDMAFullTransfer) {
generate_waveform(current_player, current_player->half_buffer_length);
handled = true;
}
Expand Down
19 changes: 12 additions & 7 deletions dtmf_dolphin_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ typedef struct {
typedef struct {
size_t buffer_length;
size_t half_buffer_length;
uint8_t *buffer_buffer;
uint16_t *sample_buffer;
uint8_t* buffer_buffer;
uint16_t* sample_buffer;
float volume;
FuriMessageQueue *queue;
DTMFDolphinOsc *osc1;
DTMFDolphinOsc *osc2;
DTMFDolphinPulseFilter *filter;
FuriMessageQueue* queue;
DTMFDolphinOsc* osc1;
DTMFDolphinOsc* osc2;
DTMFDolphinPulseFilter* filter;
bool playing;
} DTMFDolphinAudio;

Expand All @@ -42,7 +42,12 @@ void dtmf_dolphin_audio_free(DTMFDolphinAudio* player);

void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc);

bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, uint16_t pulse_ms, uint16_t gap_ms);
bool dtmf_dolphin_audio_play_tones(
float freq1,
float freq2,
uint16_t pulses,
uint16_t pulse_ms,
uint16_t gap_ms);

bool dtmf_dolphin_audio_stop_tones();

Expand Down
Loading

0 comments on commit 837ce09

Please sign in to comment.