Skip to content
File

Blob: firmware/platform/audio.c

c105 lines
1#include <stdatomic.h>
2#include <stdlib.h>
3#include <string.h>
4#include "radio_bridge.h"
5#include "dsps_fft2r.h"
6#include "esp_audio_dec.h"
7#include "esp_opus_dec.h"
8#include "esp_heap_caps.h"
9 
10#define FFT_SIZE 2048
11#define PCM_SAMPLES (960 * 2)
12_Static_assert(sizeof(float) == 4, "FFT ABI requires float32");
13 
14struct radio_dsp {
15 void *decoder;
16 esp_opus_dec_cfg_t config;
17 float *fft;
18 int16_t pcm[PCM_SAMPLES];
19 uint8_t opus[1275];
20};
21/* ESP-DSP tables are process-global. Permit one owner, with no reinitialization
22 * after Drop. There are no asynchronous decoder or FFT callbacks. */
23static atomic_bool dsp_taken;
24 
25radio_dsp *radio_dsp_open(void)
26{
27 if (atomic_exchange(&dsp_taken, true))
28 return NULL;
29 radio_dsp *d = heap_caps_calloc(1, sizeof(*d), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
30 if (!d)
31 return NULL;
32 d->fft = heap_caps_aligned_alloc(16, 2 * FFT_SIZE * sizeof(float),
33 MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
34 if (!d->fft) {
35 free(d);
36 return NULL;
37 }
38 memset(d->fft, 0, 2 * FFT_SIZE * sizeof(float));
39 d->config = (esp_opus_dec_cfg_t){.sample_rate = 48000,
40 .channel = 2,
41 .frame_duration = ESP_OPUS_DEC_FRAME_DURATION_20_MS,
42 .self_delimited = false};
43 if (esp_opus_dec_open(&d->config, sizeof(d->config), &d->decoder) != ESP_AUDIO_ERR_OK) {
44 free(d->fft);
45 free(d);
46 return NULL;
47 }
48 if (dsps_fft2r_init_fc32(NULL, FFT_SIZE) != ESP_OK) {
49 radio_dsp_free(d);
50 return NULL;
51 }
52 return d;
53}
54void radio_dsp_free(radio_dsp *d)
55{
56 if (!d)
57 return;
58 if (d->decoder)
59 esp_opus_dec_close(d->decoder);
60 dsps_fft2r_deinit_fc32();
61 free(d->fft);
62 free(d);
63}
64int32_t radio_dsp_reset(radio_dsp *d)
65{
66 return esp_opus_dec_reset(d->decoder);
67}
68int32_t radio_dsp_decode(radio_dsp *d, const uint8_t *opus, size_t length)
69{
70 if (!length || length > sizeof(d->opus))
71 return -1;
72 memcpy(d->opus, opus, length);
73 esp_audio_dec_in_raw_t input = {.buffer = d->opus, .len = length};
74 esp_audio_dec_out_frame_t output = {.buffer = (uint8_t *)d->pcm, .len = sizeof(d->pcm)};
75 esp_audio_dec_info_t info = {0};
76 int err = esp_opus_dec_decode(d->decoder, &input, &output, &info);
77 if (err)
78 return err;
79 if (input.consumed != length || output.decoded_size != sizeof(d->pcm) ||
80 info.sample_rate != 48000 || info.channel != 2 || info.bits_per_sample != 16)
81 return -1;
82 return 0;
83}
84const int16_t *radio_dsp_pcm(radio_dsp *d)
85{
86 return d->pcm;
87}
88float *radio_dsp_fft_buffer(radio_dsp *d)
89{
90 return d->fft;
91}
92int32_t radio_dsp_transform(radio_dsp *d)
93{
94 int err = dsps_fft2r_fc32(d->fft, FFT_SIZE);
95 return err ? err : dsps_bit_rev_fc32(d->fft, FFT_SIZE);
96}
97float *radio_analysis_history_alloc(void)
98{
99 return heap_caps_calloc(2 * FFT_SIZE, sizeof(float), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
100}
101void radio_analysis_history_free(float *history)
102{
103 free(history);
104}