arduino-audio-tools
AudioFaust.h
1 #pragma once
2 #include "AudioTools/AudioStreams.h"
3 #include "AudioLibs/AudioFaustDSP.h"
4 
5 namespace audio_tools {
6 
14 template<class DSP>
15 class FaustStream : public AudioStream {
16  public:
17 
19  FaustStream(bool useSeparateOutputBuffer=true) {
20  with_output_buffer = useSeparateOutputBuffer;
21  }
22 
24  FaustStream(Print &out, bool useSeparateOutputBuffer=true){
25  p_out = &out;
26  with_output_buffer = useSeparateOutputBuffer;
27  }
28 
29  ~FaustStream(){
30  end();
31  deleteFloatBuffer();
32  delete p_dsp;
33 #ifdef USE_MEMORY_MANAGER
34  DSP::classDestroy();
35 #endif
36  }
37 
38 
40  dsp *getDSP(){
41  return p_dsp;
42  }
43 
44  AudioInfo defaultConfig() {
45  AudioInfo def;
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 *write_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>(write_data, len);
151  case 16:
152  return writeT<int16_t>(write_data, len);
153  case 24:
154  return writeT<int24_t>(write_data, len);
155  case 32:
156  return writeT<int32_t>(write_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 
241  bool checkChannels() {
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
323  convertFloatBufferToInt<T>(samples, p_float_buffer, (void*) write_data);
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:51
virtual bool exists(const char *label)
checks if a label exists
Definition: AudioFaustDSP.h:129
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: AudioStreams.h:24
Integration into Faust DSP see https://faust.grame.fr/ To generate code from faust,...
Definition: AudioFaust.h:15
dsp * getDSP()
Provides a pointer to the actual dsp object.
Definition: AudioFaust.h:40
size_t readBytes(uint8_t *data, size_t len) override
Used if FaustStream is used as audio source.
Definition: AudioFaust.h:116
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
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
size_t write(const uint8_t *write_data, size_t len) override
Used if FaustStream is used as audio sink or filter.
Definition: AudioFaust.h:146
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:330
Definition: NoArduino.h:58
Memory manager which uses psram when it is available.
Definition: AudioFaustDSP.h:180
minimal dsp base class needed by Faust
Definition: AudioFaustDSP.h:24
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:57