arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AudioFaust.h
1#pragma once
2#include "AudioTools/CoreAudio/AudioStreams.h"
3#include "AudioTools/AudioLibs/AudioFaustDSP.h"
4
5namespace audio_tools {
6
14template<class DSP>
15class FaustStream : public AudioStream {
16 public:
17
20 with_output_buffer = useSeparateOutputBuffer;
21 }
22
25 p_out = &out;
26 with_output_buffer = useSeparateOutputBuffer;
27 }
28
30 end();
31 deleteFloatBuffer();
32 delete p_dsp;
33#ifdef USE_MEMORY_MANAGER
34 DSP::classDestroy();
35#endif
36 }
37
38
41 return p_dsp;
42 }
43
44 AudioInfo defaultConfig() {
46 def.channels = 2;
47 def.bits_per_sample = 16;
48 def.sample_rate = 44100;
49 return def;
50 }
51
52
54 bool begin(AudioInfo cfg){
55 TRACED();
56 bool result = true;
57 this->cfg = cfg;
58 this->bytes_per_sample = cfg.bits_per_sample / 8;
59 this->bytes_per_frame = bytes_per_sample * cfg.channels;
60 this->float_to_int_factor = NumberConverter::maxValue(cfg.bits_per_sample);
61
62 if (p_dsp==nullptr){
63#ifdef USE_MEMORY_MANAGER
64 DSP::fManager = new dsp_memory_manager();
65 DSP::memoryInfo();
66 p_dsp = DSP::create();
67#else
68 p_dsp = new DSP();
69#endif
70 }
71
72 if (p_dsp==nullptr){
73 LOGE("dsp is null");
74 return false;
75 }
76
77 DSP::classInit(cfg.sample_rate);
78 p_dsp->buildUserInterface(&ui);
79 p_dsp->init(cfg.sample_rate);
80 p_dsp->instanceInit(cfg.sample_rate);
81
82 // we do expect an output
83 result = checkChannels();
84
85 // allocate array of channel data
86 if (p_buffer==nullptr){
87 p_buffer = new FAUSTFLOAT*[cfg.channels]();
88 }
89 if (with_output_buffer && p_buffer_out==nullptr){
90 p_buffer_out = new FAUSTFLOAT*[cfg.channels]();
91 }
92
93 LOGI("is_read: %s", is_read?"true":"false");
94 LOGI("is_write: %s", is_write?"true":"false");
95 gate_exists = ui.exists("gate");
96 LOGI("gate_exists: %s", gate_exists?"true":"false");
97
98 return result;
99 }
100
101
103 void end() {
104 TRACED();
105 is_read = false;
106 is_write = false;
107 p_dsp->instanceClear();
108#ifdef USE_MEMORY_MANAGER
109 DSP::destroy(p_dsp);
110 p_dsp = nullptr;
111#endif
112
113 }
114
116 size_t readBytes(uint8_t *data, size_t len) override {
117 size_t result = 0;
118 if (is_read){
119 TRACED();
120 result = len;
121 int samples = len / bytes_per_sample;
122 allocateFloatBuffer(samples, false);
123 p_dsp->compute(samples, nullptr, p_buffer);
124 // convert from float to int
125 switch(cfg.bits_per_sample){
126 case 8:
127 convertFloatBufferToInt<int8_t>(samples, p_buffer, data);
128 break;
129 case 16:
130 convertFloatBufferToInt<int16_t>(samples, p_buffer, data);
131 break;
132 case 24:
133 convertFloatBufferToInt<int24_t>(samples, p_buffer, data);
134 break;
135 case 32:
136 convertFloatBufferToInt<int32_t>(samples, p_buffer, data);
137 break;
138 default:
139 TRACEE();
140 }
141 }
142 return result;
143 }
144
146 size_t write(const uint8_t *data, size_t len) override {
147 LOGD("FaustStream::write: %d", len);
148 switch(cfg.bits_per_sample){
149 case 8:
150 return writeT<int8_t>(data, len);
151 case 16:
152 return writeT<int16_t>(data, len);
153 case 24:
154 return writeT<int24_t>(data, len);
155 case 32:
156 return writeT<int32_t>(data, len);
157 default:
158 TRACEE();
159 }
160 return 0;
161 }
162
163 int available() override {
164 return DEFAULT_BUFFER_SIZE;
165 }
166
167 int availableForWrite() override {
168 return DEFAULT_BUFFER_SIZE / bytes_per_frame; // we limit the write size
169 }
170
172 virtual FAUSTFLOAT labelValue(const char*label) {
173 return ui.getValue(label);
174 }
175
177 virtual bool setLabelValue(const char*label, FAUSTFLOAT value){
178 if (!is_read && !is_write) LOGE("setLabelValue must be called after begin");
179 bool result = ui.setValue(label, value);
180 LOGI("setLabelValue('%s',%f) -> %s", label, value, result?"true":"false");
181 return result;
182 }
183
184 virtual bool setMidiNote(int note){
185 FAUSTFLOAT frq = noteToFrequency(note);
186 return setFrequency(frq);
187 }
188
189 virtual bool setFrequency(FAUSTFLOAT freq){
190 return setLabelValue("freq", freq);
191 }
192
193 virtual FAUSTFLOAT frequency() {
194 return labelValue("freq");
195 }
196
197 virtual bool setBend(FAUSTFLOAT bend){
198 return setLabelValue("bend", bend);
199 }
200
201 virtual FAUSTFLOAT bend() {
202 return labelValue("bend");
203 }
204
205 virtual bool setGain(FAUSTFLOAT gain){
206 return setLabelValue("gain", gain);
207 }
208
209 virtual FAUSTFLOAT gain() {
210 return labelValue("gain");
211 }
212
213 virtual bool midiOn(int note, FAUSTFLOAT gain){
214 if (gate_exists) setLabelValue("gate",1.0);
215 return setMidiNote(note) && setGain(gain);
216 }
217
218 virtual bool midiOff(int note){
219 if (gate_exists) setLabelValue("gate",0.0);
220 return setMidiNote(note) && setGain(0.0);
221 }
222
223 protected:
224 bool is_init = false;
225 bool is_read = false;
226 bool is_write = false;
227 bool gate_exists = false;
228 bool with_output_buffer;
229 int bytes_per_sample;
230 int bytes_per_frame;
231 int buffer_allocated;
232 float float_to_int_factor = 32767;
233 DSP *p_dsp = nullptr;
234 AudioInfo cfg;
235 Print *p_out=nullptr;
236 FAUSTFLOAT** p_buffer=nullptr;
237 FAUSTFLOAT** p_buffer_out=nullptr;
238 UI ui;
239
242 bool result = true;
243
244 // update channels
245 int num_outputs = p_dsp->getNumOutputs();
246 if (cfg.channels!=num_outputs){
247 cfg.channels = num_outputs;
248 LOGW("Updating channels to %d", num_outputs);
249 }
250
251 if (num_outputs>0){
252 if (num_outputs==cfg.channels){
253 is_read = true;
254 } else {
255 LOGE("NumOutputs %d is not matching with number of channels %d", num_outputs, cfg.channels);
256 result = false;
257 }
258 if (p_dsp->getNumInputs()!=0 && p_dsp->getNumInputs()!=cfg.channels){
259 LOGE("NumInputs is not matching with number of channels");
260 result = false;
261 }
262 if (p_dsp->getNumInputs()>0){
263 if (p_out!=nullptr){
264 is_write = true;
265 } else {
266 LOGE("Faust expects input - you need to provide and AudioStream in the constructor");
267 result = false;
268 }
269 }
270 }
271 return result;
272 }
273
275 template <class T>
276 void convertFloatBufferToInt(int samples, FAUSTFLOAT**p_float_in, void *data_out){
277 T *dataT = (T*) data_out;
278 int frameCount = samples/cfg.channels;
279 for (int j=0; j<frameCount; j++){
280 for (int i=0;i<cfg.channels;i++){
281 float sample = p_float_in[i][j];
282 // clip input
283 if(sample > 1.0f){
284 sample = 1.0f;
285 }
286 if(sample < -1.0f){
287 sample = -1.0f;
288 }
289 dataT[(j*cfg.channels)+i] = sample * float_to_int_factor;
290 }
291 }
292 }
293
295 template <class T>
296 void convertIntBufferToFloat(int samples, void *data_in, FAUSTFLOAT**p_float_out ){
297 T *dataT = (T*) data_in;
298 int frameCount = samples/cfg.channels;
299 for(int j=0;j<frameCount;j++){
300 for(int i=0;i<cfg.channels;i++){
301 p_float_out[i][j] = static_cast<FAUSTFLOAT>(dataT[(j*cfg.channels)+i]) / float_to_int_factor;
302 }
303 }
304 }
305
307 template <class T>
308 size_t writeT(const uint8_t *write_data, size_t len) {
309 size_t result = 0;
310 if (is_write){
311 TRACED();
312 int samples = len / bytes_per_sample;
313 int frames = samples / cfg.channels;
314 // prepare float input for faust
315 allocateFloatBuffer(samples, with_output_buffer);
316 convertIntBufferToFloat<T>(samples, (void*) write_data, p_buffer);
317
318 // determine result
319 FAUSTFLOAT** p_float_buffer = with_output_buffer ? p_buffer_out : p_buffer;
320 p_dsp->compute(frames, p_buffer, p_float_buffer);
321
322 // update buffer with data from faust
324 // write data to final output
325 result = p_out->write(write_data, len);
326 }
327 return result;
328 }
329
330
332 void allocateFloatBuffer(int samples, bool allocate_out){
333 if (samples>buffer_allocated){
334 if (p_buffer[0]!=nullptr){
335 for (int j=0;j<cfg.channels;j++){
336 delete[]p_buffer[j];
337 p_buffer[j] = nullptr;
338 }
339 }
340 if (p_buffer_out!=nullptr && p_buffer_out[0]!=nullptr){
341 for (int j=0;j<cfg.channels;j++){
342 delete[]p_buffer_out[j];
343 p_buffer_out[j] = nullptr;
344 }
345 }
346 }
347 if (p_buffer[0]==nullptr){
348 const int ch = cfg.channels;
349 for (int j=0;j<ch;j++){
350 p_buffer[j] = new FAUSTFLOAT[samples];
351 }
352 buffer_allocated = samples;
353 }
354 if (allocate_out){
355 if (p_buffer_out[0]==nullptr){
356 const int ch = cfg.channels;
357 for (int j=0;j<ch;j++){
358 p_buffer_out[j] = new FAUSTFLOAT[samples];
359 }
360 }
361 }
362 }
363
364 void deleteFloatBuffer() {
365 if (p_buffer!=nullptr) {
366 for (int j=0;j<cfg.channels;j++){
367 if (p_buffer[j]!=nullptr) delete p_buffer[j];
368 }
369 delete[] p_buffer;
370 p_buffer = nullptr;
371 }
372 if (p_buffer_out!=nullptr) {
373 for (int j=0;j<cfg.channels;j++){
374 if (p_buffer_out[j]!=nullptr) delete p_buffer_out[j];
375 }
376 delete[] p_buffer_out;
377 p_buffer_out = nullptr;
378 }
379 }
380
381 FAUSTFLOAT noteToFrequency(uint8_t x) {
382 FAUSTFLOAT note = x;
383 return 440.0 * pow(2.0f, (note-69)/12);
384 }
385
386};
387
388
389} // namespace
390
391
Minimum implementation of UI parameters. We only support the setting and getting of values.
Definition AudioFaustDSP.h:52
virtual bool exists(const char *label)
checks if a label exists
Definition AudioFaustDSP.h:130
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:115
Integration into Faust DSP see https://faust.grame.fr/ To generate code from faust,...
Definition AudioFaust.h:15
size_t readBytes(uint8_t *data, size_t len) override
Used if FaustStream is used as audio source.
Definition AudioFaust.h:116
size_t write(const uint8_t *data, size_t len) override
Used if FaustStream is used as audio sink or filter.
Definition AudioFaust.h:146
FaustStream(Print &out, bool useSeparateOutputBuffer=true)
Constructor for Faust as Singal Processor - changing an input signal and sending it to out.
Definition AudioFaust.h:24
FaustStream(bool useSeparateOutputBuffer=true)
Constructor for Faust as Audio Source.
Definition AudioFaust.h:19
virtual FAUSTFLOAT labelValue(const char *label)
Determines the value of a parameter.
Definition AudioFaust.h:172
void convertFloatBufferToInt(int samples, FAUSTFLOAT **p_float_in, void *data_out)
Converts the float buffer to int values.
Definition AudioFaust.h:276
void convertIntBufferToFloat(int samples, void *data_in, FAUSTFLOAT **p_float_out)
Converts the int buffer to float values.
Definition AudioFaust.h:296
bool checkChannels()
Checks the input and output channels and updates the is_write or is_read scenario flags.
Definition AudioFaust.h:241
void end()
Ends the processing.
Definition AudioFaust.h:103
size_t writeT(const uint8_t *write_data, size_t len)
Used if FaustStream is used as audio sink or filter.
Definition AudioFaust.h:308
dsp * getDSP()
Provides a pointer to the actual dsp object.
Definition AudioFaust.h:40
void allocateFloatBuffer(int samples, bool allocate_out)
Allocate the buffer that is needed by faust.
Definition AudioFaust.h:332
bool begin(AudioInfo cfg)
Checks the parameters and starts the processing.
Definition AudioFaust.h:54
virtual bool setLabelValue(const char *label, FAUSTFLOAT value)
Defines the value of a parameter.
Definition AudioFaust.h:177
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition AudioTypes.h:317
Definition NoArduino.h:62
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Memory manager which uses psram when it is available.
Definition AudioFaustDSP.h:181
minimal dsp base class needed by Faust
Definition AudioFaustDSP.h:25
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioConfig.h:885
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:52
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59