1 /************************** BEGIN esp32audio.h **************************/
2 /************************************************************************
3  FAUST Architecture File
4  Copyright (C) 2020 GRAME, Centre National de Creation Musicale
5  ---------------------------------------------------------------------
6  This Architecture section is free software; you can redistribute it
7  and/or modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 3 of
9  the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; If not, see <http://www.gnu.org/licenses/>.
18 
19  EXCEPTION : As a special exception, you may create a larger work
20  that contains this FAUST architecture section and distribute
21  that work under terms of your choice, so long as this FAUST
22  architecture section is not modified.
23  ************************************************************************/
24 
25 #ifndef __esp32audio__
26 #define __esp32audio__
27 
28 #include <utility>
29 
30 #include "freertos/FreeRTOS.h"
31 #include "freertos/task.h"
32 #include "driver/i2s.h"
33 
34 #include "faust/audio/audio.h"
35 #include "faust/dsp/dsp.h"
36 
37 #define MULT_S32 2147483647
38 #define DIV_S32 4.6566129e-10
39 #define clip(sample) std::max(-MULT_S32, std::min(MULT_S32, ((int32_t)(sample * MULT_S32))));
40 
41 #define AUDIO_MAX_CHAN 2
42 
43 class esp32audio : public audio {
44 
45     private:
46 
47         int fSampleRate;
48         int fBufferSize;
49         int fNumInputs;
50         int fNumOutputs;
51         float** fInChannel;
52         float** fOutChannel;
53         TaskHandle_t fHandle;
54         dsp* fDSP;
55         bool fRunning;
56 
57         template <int INPUTS, int OUTPUTS>
audioTask()58         void audioTask()
59         {
60             while (fRunning) {
61                 if (INPUTS > 0) {
62                     // Read from the card
63                     int32_t samples_data_in[AUDIO_MAX_CHAN*fBufferSize];
64                     size_t bytes_read = 0;
65                     i2s_read((i2s_port_t)0, &samples_data_in, AUDIO_MAX_CHAN*sizeof(float)*fBufferSize, &bytes_read, portMAX_DELAY);
66 
67                     // Convert and copy inputs
68                     if (INPUTS == AUDIO_MAX_CHAN) {
69                         // if stereo
70                         for (int i = 0; i < fBufferSize; i++) {
71                             fInChannel[0][i] = (float)samples_data_in[i*AUDIO_MAX_CHAN]*DIV_S32;
72                             fInChannel[1][i] = (float)samples_data_in[i*AUDIO_MAX_CHAN+1]*DIV_S32;
73                         }
74                     } else {
75                         // otherwise only first channel
76                         for (int i = 0; i < fBufferSize; i++) {
77                             fInChannel[0][i] = (float)samples_data_in[i*AUDIO_MAX_CHAN]*DIV_S32;
78                         }
79                     }
80                 }
81 
82                 // Call DSP
83                 fDSP->compute(fBufferSize, fInChannel, fOutChannel);
84 
85                 // Convert and copy outputs
86                 int32_t samples_data_out[AUDIO_MAX_CHAN*fBufferSize];
87                 if (OUTPUTS == AUDIO_MAX_CHAN) {
88                     // if stereo
89                     for (int i = 0; i < fBufferSize; i++) {
90                         samples_data_out[i*AUDIO_MAX_CHAN] = clip(fOutChannel[0][i]);
91                         samples_data_out[i*AUDIO_MAX_CHAN+1] = clip(fOutChannel[1][i]);
92                     }
93                 } else {
94                     // otherwise only first channel
95                     for (int i = 0; i < fBufferSize; i++) {
96                         samples_data_out[i*AUDIO_MAX_CHAN] = clip(fOutChannel[0][i]);
97                         samples_data_out[i*AUDIO_MAX_CHAN+1] = samples_data_out[i*AUDIO_MAX_CHAN];
98                     }
99                 }
100 
101                 // Write to the card
102                 size_t bytes_written = 0;
103                 i2s_write((i2s_port_t)0, &samples_data_out, AUDIO_MAX_CHAN*sizeof(float)*fBufferSize, &bytes_written, portMAX_DELAY);
104             }
105 
106             // Task has to deleted itself beforee returning
107             vTaskDelete(nullptr);
108         }
109 
destroy()110         void destroy()
111         {
112             for (int i = 0; i < fNumInputs; i++) {
113                 delete[] fInChannel[i];
114             }
115             delete [] fInChannel;
116 
117             for (int i = 0; i < fNumOutputs; i++) {
118                 delete[] fOutChannel[i];
119             }
120             delete [] fOutChannel;
121         }
122 
audioTaskHandler(void * arg)123         static void audioTaskHandler(void* arg)
124         {
125             esp32audio* audio = static_cast<esp32audio*>(arg);
126 
127             if (audio->fNumInputs == 0 && audio->fNumOutputs == 1) {
128                 audio->audioTask<0,1>();
129             } else if (audio->fNumInputs == 0 && audio->fNumOutputs == 2) {
130                 audio->audioTask<0,2>();
131             } else if (audio->fNumInputs == 1 && audio->fNumOutputs == 1) {
132                 audio->audioTask<1,1>();
133             } else if (audio->fNumInputs == 1 && audio->fNumOutputs == 2) {
134                 audio->audioTask<1,2>();
135             } else if (audio->fNumInputs == 2 && audio->fNumOutputs == 1) {
136                 audio->audioTask<2,1>();
137             } else if (audio->fNumInputs == 2 && audio->fNumOutputs == 2) {
138                 audio->audioTask<2,2>();
139             }
140         }
141 
142     public:
143 
esp32audio(int srate,int bsize)144         esp32audio(int srate, int bsize):
145         fSampleRate(srate),
146         fBufferSize(bsize),
147         fNumInputs(0),
148         fNumOutputs(0),
149         fInChannel(nullptr),
150         fOutChannel(nullptr),
151         fHandle(nullptr),
152         fDSP(nullptr),
153         fRunning(false)
154         {
155             i2s_pin_config_t pin_config;
156         #if TTGO_TAUDIO
157             pin_config = {
158                 .bck_io_num = 33,
159                 .ws_io_num = 25,
160                 .data_out_num = 26,
161                 .data_in_num = 27
162             };
163         #elif A1S_BOARD
164             pin_config = {
165                 .bck_io_num = 27,
166                 .ws_io_num = 26,
167                 .data_out_num = 25,
168                 .data_in_num = 35
169             };
170         #elif LYRA_T
171             pin_config = {
172                 .bck_io_num = 5,
173                 .ws_io_num = 25,
174                 .data_out_num = 26,
175                 .data_in_num = 35
176             };
177         #else // Default
178             pin_config = {
179                 .bck_io_num = 33,
180                 .ws_io_num = 25,
181                 .data_out_num = 26,
182                 .data_in_num = 27
183             };
184         #endif
185 
186         #if A1S_BOARD
187             i2s_config_t i2s_config = {
188                 .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
189                 .sample_rate = fSampleRate,
190                 .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
191                 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
192                 .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
193                 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL3, // high interrupt priority
194                 .dma_buf_count = 3,
195                 .dma_buf_len = fBufferSize,
196                 .use_apll = true
197             };
198         #else // default
199             i2s_config_t i2s_config = {
200                 .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
201                 .sample_rate = fSampleRate,
202                 .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
203                 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
204                 .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
205                 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
206                 .dma_buf_count = 3,
207                 .dma_buf_len = fBufferSize,
208                 .use_apll = false
209             };
210         #endif
211             i2s_driver_install((i2s_port_t)0, &i2s_config, 0, nullptr);
212             i2s_set_pin((i2s_port_t)0, &pin_config);
213             PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
214             REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
215         }
216 
~esp32audio()217         virtual ~esp32audio()
218         {
219             destroy();
220         }
221 
init(const char * name,dsp * dsp)222         virtual bool init(const char* name, dsp* dsp)
223         {
224             destroy();
225 
226             fDSP = dsp;
227             fNumInputs = fDSP->getNumInputs();
228             fNumOutputs = fDSP->getNumOutputs();
229 
230             fDSP->init(fSampleRate);
231 
232             if (fNumInputs > 0) {
233                 fInChannel = new FAUSTFLOAT*[fNumInputs];
234                 for (int i = 0; i < fNumInputs; i++) {
235                     fInChannel[i] = new FAUSTFLOAT[fBufferSize];
236                 }
237             } else {
238                 fInChannel = nullptr;
239             }
240 
241             if (fNumOutputs > 0) {
242                 fOutChannel = new FAUSTFLOAT*[fNumOutputs];
243                 for (int i = 0; i < fNumOutputs; i++) {
244                     fOutChannel[i] = new FAUSTFLOAT[fBufferSize];
245                 }
246             } else {
247                 fOutChannel = nullptr;
248             }
249 
250             return true;
251         }
252 
start()253         virtual bool start()
254         {
255             if (!fRunning) {
256                 fRunning = true;
257                 return (xTaskCreatePinnedToCore(audioTaskHandler, "Faust DSP Task", 4096, (void*)this, 24, &fHandle, 0) == pdPASS);
258             } else {
259                 return true;
260             }
261         }
262 
stop()263         virtual void stop()
264         {
265             if (fRunning) {
266                 fRunning = false;
267                 vTaskDelay(1/portTICK_PERIOD_MS);
268                 fHandle = nullptr;
269             }
270         }
271 
getBufferSize()272         virtual int getBufferSize() { return fBufferSize; }
getSampleRate()273         virtual int getSampleRate() { return fSampleRate; }
274 
getNumInputs()275         virtual int getNumInputs() { return AUDIO_MAX_CHAN; }
getNumOutputs()276         virtual int getNumOutputs() { return AUDIO_MAX_CHAN; }
277 
278         // Returns the average proportion of available CPU being spent inside the audio callbacks (between 0 and 1.0).
getCPULoad()279         virtual float getCPULoad() { return 0.f; }
280 
281 };
282 
283 #endif
284 /**************************  END  esp32audio.h **************************/
285