Libarary: big code update from my Tympan_Library

pull/5/head
Chip Audette 7 years ago
parent d46ab56ed7
commit 81492cc5ac
  1. 2
      AudioCalcEnvelope_F32.h
  2. 107
      AudioCalcGainWDRC_F32.h
  3. 82
      AudioConfigFIRFilterBank_F32.cpp
  4. 78
      AudioConfigFIRFilterBank_F32.h
  5. 101
      AudioControlTester.cpp
  6. 538
      AudioControlTester.h
  7. 2
      AudioConvert_F32.h
  8. 187
      AudioEffectCompWDRC_F32.h
  9. 19
      AudioEffectCompressor_F32.h
  10. 1
      AudioEffectEmpty_F32.h
  11. 5
      AudioEffectGain_F32.h
  12. 41
      AudioFilterBiquad_F32.cpp
  13. 204
      AudioFilterBiquad_F32.h
  14. 55
      AudioFilterFIR_F32.cpp
  15. 55
      AudioFilterFIR_F32.h
  16. 30
      AudioMixer4_F32.cpp
  17. 38
      AudioMixer4_F32.h
  18. 16
      AudioMixer_F32.h
  19. 2
      AudioMultiply_F32.h
  20. 29
      AudioSettings_F32.cpp
  21. 18
      AudioSettings_F32.h
  22. 18
      AudioStream_F32.cpp
  23. 61
      AudioStream_F32.h
  24. 181
      BTNRH_WDRC_Types.h
  25. 19
      OpenAudio_ArduinoLibrary.h
  26. 146
      USB_Audio_F32.h
  27. 98
      control_tlv320aic3206.cpp
  28. 6
      control_tlv320aic3206.h
  29. 4
      examples/BasicCompressor_Float/BasicCompressor_Float.ino
  30. 2
      examples/BasicGain_Float/BasicGain_Float.ino
  31. 6
      examples/MixStereoToMono_Float/MixStereoToMono_Float.ino
  32. 4
      examples/MyAudioEffect_Float/MyAudioEffect_Float.ino
  33. 8
      examples/OscillatorWithPitchmod_Float/OscillatorWithPitchmod_Float.ino
  34. 2
      output_i2s_f32.cpp
  35. 2
      play_queue_f32.h
  36. 2
      record_queue_f32.h
  37. 11
      synth_pinknoise_f32.h
  38. 2
      synth_sine_f32.cpp
  39. 5
      synth_whitenoise_f32.h
  40. 393
      utility/BTNRH_rfft.cpp
  41. 19
      utility/BTNRH_rfft.h
  42. 384
      utility/rfft.c

@ -47,7 +47,7 @@ class AudioCalcEnvelope_F32 : public AudioStream_F32
audio_block_f32_t *out_block = AudioStream_F32::allocate_f32();
if (!out_block) return;
// //////////////////////add your processing here!
// /////////// put the actual processing here
smooth_env(in_block->data, out_block->data, in_block->length);
out_block->length = in_block->length; out_block->fs_Hz = in_block->fs_Hz;

@ -17,17 +17,8 @@
#include <arm_math.h> //ARM DSP extensions. for speed!
#include <AudioStream_F32.h>
#include "BTNRH_WDRC_Types.h"
typedef struct {
float attack; // attack time (ms), unused in this class
float release; // release time (ms), unused in this class
float fs; // sampling rate (Hz), set through other means in this class
float maxdB; // maximum signal (dB SPL)...I think this is the SPL corresponding to signal with rms of 1.0
float tkgain; // compression-start gain
float tk; // compression-start kneepoint
float cr; // compression ratio
float bolt; // broadband output limiting threshold
} CHA_WDRC;
class AudioCalcGainWDRC_F32 : public AudioStream_F32
@ -35,9 +26,10 @@ class AudioCalcGainWDRC_F32 : public AudioStream_F32
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName:calc_WDRCGain
public:
//default constructor
//constructors
AudioCalcGainWDRC_F32(void) : AudioStream_F32(1, inputQueueArray_f32) { setDefaultValues(); };
AudioCalcGainWDRC_F32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32) { setDefaultValues(); };
//here's the method that does all the work
void update(void) {
@ -49,7 +41,7 @@ class AudioCalcGainWDRC_F32 : public AudioStream_F32
audio_block_f32_t *out_block = AudioStream_F32::allocate_f32();
if (!out_block) return;
// //////////////////////add your processing here!
// ////////////////////// do the processing here!
calcGainFromEnvelope(in_block->data, out_block->data, in_block->length);
out_block->length = in_block->length; out_block->fs_Hz = in_block->fs_Hz;
@ -69,7 +61,7 @@ class AudioCalcGainWDRC_F32 : public AudioStream_F32
audio_block_f32_t *env_dB_block = AudioStream_F32::allocate_f32();
if (!env_dB_block) return;
//convert to dB
//convert to dB and calibrate (via maxdB)
for (int k=0; k < n; k++) env_dB_block->data[k] = maxdB + db2(env[k]); //maxdb in the private section
// apply wide-dynamic range compression
@ -80,48 +72,60 @@ class AudioCalcGainWDRC_F32 : public AudioStream_F32
//original call to WDRC_circuit
//void WDRC_circuit(float *x, float *y, float *pdb, int n, float tkgn, float tk, float cr, float bolt)
//void WDRC_circuit(float *orig_signal, float *signal_out, float *env_dB, int n, float tkgn, float tk, float cr, float bolt)
//modified to output the gain instead of the fully processed signal
//modified to output just the gain instead of the fully processed signal
void WDRC_circuit_gain(float *env_dB, float *gain_out, const int n,
const float tkgn, const float tk, const float cr, const float bolt) {
const float tkgn, const float tk, const float cr, const float bolt)
//tkgn = gain (dB?) at start of compression (ie, gain for linear behavior?)
//tk = compression start kneepoint (pre-compression, dB SPL?)
//cr = compression ratio
//bolt = broadband output limiting threshold (post-compression, dB SPL?)
{
//tkgain = 30; tk = 50; bolt = 100; cr = 3;
float gdb, tkgo, pblt;
int k;
float *pdb = env_dB; //just rename it to keep the code below unchanged
float tk_tmp = tk;
float *pdb = env_dB; //just rename it to keep the code below unchanged (input SPL dB)
float tk_tmp = tk; //temporary, threshold for start of compression (input SPL dB)
if ((tk_tmp + tkgn) > bolt) {
tk_tmp = bolt - tkgn;
if ((tk_tmp + tkgn) > bolt) { //after gain, would the compression threshold be above the output-limitting threshold ("bolt")
tk_tmp = bolt - tkgn; //if so, lower the compression threshold to be the pre-gain value resulting in "bolt"
}
tkgo = tkgn + tk_tmp * (1.0f - 1.0f / cr);
pblt = cr * (bolt - tkgo);
const float cr_const = ((1.0f / cr) - 1.0f);
for (k = 0; k < n; k++) {
if ((pdb[k] < tk_tmp) && (cr >= 1.0f)) {
gdb = tkgn;
} else if (pdb[k] > pblt) {
gdb = bolt + ((pdb[k] - pblt) / 10.0f) - pdb[k];
tkgo = tkgn + tk_tmp * (1.0f - 1.0f / cr); //intermediate calc
pblt = cr * (bolt - tkgo); //calc input level (dB) where we need to start limiting, no just compression
const float cr_const = ((1.0f / cr) - 1.0f); //pre-calc a constant that we'll need later
for (k = 0; k < n; k++) { //loop over each sample
if ((pdb[k] < tk_tmp) && (cr >= 1.0f)) { //if below threshold and we're compressing
gdb = tkgn; //we're in the linear region. Apply linear gain.
} else if (pdb[k] > pblt) { //we're beyond the compression region into the limitting region
gdb = bolt + ((pdb[k] - pblt) / 10.0f) - pdb[k]; //10:1 limiting!
} else {
gdb = cr_const * pdb[k] + tkgo;
gdb = cr_const * pdb[k] + tkgo;
}
gain_out[k] = undb2(gdb);
//y[k] = x[k] * undb2(gdb); //apply the gain
}
}
last_gain = gain_out[n-1]; //hold this value, in case the user asks for it later (not needed for the algorithm)
}
void setDefaultValues(void) {
CHA_WDRC gha = {1.0f, // attack time (ms), IGNORED HERE
50.0f, // release time (ms), IGNORED HERE
24000.0f, // fs, sampling rate (Hz), IGNORED HERE
119.0f, // maxdB, maximum signal (dB SPL)
0.0f, // tkgain, compression-start gain
105.0f, // tk, compression-start kneepoint
10.0f, // cr, compression ratio
105.0f // bolt, broadband output limiting threshold
void setDefaultValues(void) { //set as limiter
BTNRH_WDRC::CHA_WDRC gha = {
5.0f, // attack time (ms)
50.0f, // release time (ms)
24000.0f, // fs, sampling rate (Hz), THIS IS IGNORED!
115.0f, // maxdB, maximum signal (dB SPL)...assumed SPL for full-scale input signal
0.0f, // tkgain, compression-start gain (dB)
55.0f, // tk, compression-start kneepoint (dB SPL)
1.0f, // cr, compression ratio (set to 1.0 to defeat)
100.0f // bolt, broadband output limiting threshold (ie, the limiter. SPL. 10:1 comp ratio)
};
//setParams(gha.maxdB, gha.tkgain, gha.cr, gha.tk, gha.bolt); //also sets calcEnvelope
setParams_from_CHA_WDRC(&gha);
}
void setParams_from_CHA_WDRC(CHA_WDRC *gha) {
void setParams_from_CHA_WDRC(BTNRH_WDRC::CHA_WDRC *gha) {
setParams(gha->maxdB, gha->tkgain, gha->cr, gha->tk, gha->bolt); //also sets calcEnvelope
}
void setParams(float _maxdB, float _tkgain, float _cr, float _tk, float _bolt) {
@ -131,7 +135,27 @@ class AudioCalcGainWDRC_F32 : public AudioStream_F32
cr = _cr;
bolt = _bolt;
}
void setKneeLimiter_dBSPL(float _bolt) { bolt = _bolt; }
void setKneeLimiter_dBFS(float _bolt_dBFS) { //convert to dB SPL
float bolt_dBSPL = maxdB + _bolt_dBFS;
setKneeLimiter_dBSPL(bolt_dBSPL);
}
void setGain_dB(float _gain_dB) { tkgn = _gain_dB; } //gain at start of compression
void setKneeCompressor_dBSPL(float _tk) { tk = _tk; }
void setKneeCompressor_dBFS(float _tk_dBFS) { // convert to dB SPL
float tk_dBSPL = maxdB + _tk_dBFS;
setKneeCompressor_dBSPL(tk_dBSPL);
}
void setCompRatio(float _cr) { cr = _cr; };
void setMaxdB(float _maxdB) { maxdB = _maxdB; }
float getGain_dB(void) { return tkgn; } //returns the linear gain of the system
float getCurrentGain(void) { return last_gain; }
float getCurrentGain_dB(void) { return db2(getCurrentGain()); }
//dB functions. Feed it the envelope amplitude (not squared) and it computes 20*log10(x) or it does 10.^(x/20)
static float undb2(const float &x) { return expf(0.11512925464970228420089957273422f*x); } //faster: exp(log(10.0f)*x/20); this is exact
static float db2(const float &x) { return 6.020599913279623f*log2f_approx(x); } //faster: 20*log2_approx(x)/log2(10); this is approximate
@ -168,6 +192,7 @@ class AudioCalcGainWDRC_F32 : public AudioStream_F32
private:
audio_block_f32_t *inputQueueArray_f32[1]; //memory pointer for the input to this module
float maxdB, tkgn, tk, cr, bolt;
float last_gain = 1.0; //what was the last gain value computed for the signal
};
#endif

@ -0,0 +1,82 @@
/*
* fir_filterbank.cpp
*
* Created: Chip Audette, Creare LLC, Feb 2017
* Primarly built upon CHAPRO "Generic Hearing Aid" from
* Boys Town National Research Hospital (BTNRH): https://github.com/BTNRH/chapro
*
* License: MIT License. Use at your own risk.
*
*/
#include "AudioConfigFIRFilterBank_F32.h"
#include "utility/BTNRH_rfft.h"
void AudioConfigFIRFilterBank_F32::fir_filterbank(float *bb, float *cf, const int nc, const int nw_orig, const int wt, const float sr)
{
double p, w, a = 0.16, sm = 0;
float *ww, *bk, *xx, *yy;
int j, k, kk, nt, nf, ns, *be;
int nw = nextPowerOfTwo(nw_orig);
//Serial.print("AudioConfigFIRFilterBank: fir_filterbank: nw_orig = "); Serial.print(nw_orig);
//Serial.print(", nw = "); Serial.println(nw);
nt = nw * 2; //we're going to do an fft that's twice as long (zero padded)
nf = nw + 1; //number of bins to nyquist in the zero-padded FFT. Also nf = nt/2+1
ns = nf * 2;
be = (int *) calloc(nc + 1, sizeof(int));
ww = (float *) calloc(nw, sizeof(float));
xx = (float *) calloc(ns, sizeof(float));
yy = (float *) calloc(ns, sizeof(float));
// window
for (j = 0; j < nw; j++) ww[j]=0.0f; //clear
for (j = 0; j < nw_orig; j++) {
p = M_PI * (2.0 * j - nw_orig) / nw_orig;
if (wt == 0) {
w = 0.54 + 0.46 * cos(p); // Hamming
} else if (wt==1) {
w = (1 - a + cos(p) + a * cos(2 * p)) / 2; // Blackman
} else {
//win = (1 - cos(2*pi*[1:N]/(N+1)))/2; //WEA's matlab call, indexing starts from 1, not zero
w = (1.0 - cosf(2.0*M_PI*((float)(j))/((float)(nw_orig-1))))/2.0;
}
sm += w;
ww[j] = (float) w;
}
// frequency bands...add the DC-facing band and add the Nyquist-facing band
be[0] = 0;
for (k = 1; k < nc; k++) {
kk = round(nf * cf[k - 1] * (2 / sr)); //original
be[k] = (kk > nf) ? nf : kk;
}
be[nc] = nf;
// channel tranfer functions
fzero(xx, ns);
xx[nw_orig / 2] = 1; //make a single-sample impulse centered on our eventual window
BTNRH_FFT::cha_fft_rc(xx, nt);
for (k = 0; k < nc; k++) {
fzero(yy, ns); //zero the temporary output
//int nbins = (be[k + 1] - be[k]) * 2; Serial.print("fir_filterbank: chan ");Serial.print(k); Serial.print(", nbins = ");Serial.println(nbins);
fcopy(yy + be[k] * 2, xx + be[k] * 2, (be[k + 1] - be[k]) * 2); //copy just our passband
BTNRH_FFT::cha_fft_cr(yy, nt); //IFFT back into the time domain
// apply window to iFFT of bandpass
for (j = 0; j < nw; j++) {
yy[j] *= ww[j];
}
bk = bb + k * nw_orig; //pointer to location in output array
fcopy(bk, yy, nw_orig); //copy the filter coefficients to the output array
//print out the coefficients
//for (int i=0; i<nw; i++) { Serial.print(yy[i]*1000.0f);Serial.print(" "); }; Serial.println();
}
free(be);
free(ww);
free(xx);
free(yy);
}

@ -12,7 +12,8 @@
#ifndef AudioConfigFIRFilterBank_F32_h
#define AudioConfigFIRFilterBank_F32_h
#include "utility/rfft.c"
//include <Tympan_Library.h>
#include <OpenAudio_ArduinoLibrary.h>
#define fmove(x,y,n) memmove(x,y,(n)*sizeof(float))
#define fcopy(x,y,n) memcpy(x,y,(n)*sizeof(float))
@ -22,9 +23,10 @@ class AudioConfigFIRFilterBank_F32 {
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName:config_FIRbank
public:
AudioConfigFIRFilterBank_F32(void) {
}
AudioConfigFIRFilterBank_F32(const int n_chan, const int n_fir, const float sample_rate_Hz, float *corner_freq, float *filter_coeff) {
AudioConfigFIRFilterBank_F32(void) {}
AudioConfigFIRFilterBank_F32(const AudioSettings_F32 &settings) {}
AudioConfigFIRFilterBank_F32(const int n_chan, const int n_fir, const float sample_rate_Hz, float *corner_freq, float *filter_coeff)
{
createFilterCoeff(n_chan, n_fir, sample_rate_Hz, corner_freq, filter_coeff);
}
@ -51,7 +53,7 @@ class AudioConfigFIRFilterBank_F32 {
flag__free_cf = 1;
computeLogSpacedCornerFreqs(n_chan, sample_rate_Hz, cf);
}
const int window_type = 0; //0 = Hamming
const int window_type = 0; //0 = Hamming, 1=Blackmann, 2 = Hanning
fir_filterbank(filter_coeff, cf, n_chan, n_fir, window_type, sample_rate_Hz);
if (flag__free_cf) free(cf);
}
@ -84,71 +86,7 @@ class AudioConfigFIRFilterBank_F32 {
return n;
}
void fir_filterbank(float *bb, float *cf, const int nc, const int nw_orig, const int wt, const float sr)
{
double p, w, a = 0.16, sm = 0;
float *ww, *bk, *xx, *yy;
int j, k, kk, nt, nf, ns, *be;
int nw = nextPowerOfTwo(nw_orig);
Serial.print("fir_filterbank: nw_orig = "); Serial.print(nw_orig);
Serial.print(", nw = "); Serial.println(nw);
nt = nw * 2;
nf = nw + 1;
ns = nf * 2;
be = (int *) calloc(nc + 1, sizeof(int));
ww = (float *) calloc(nw, sizeof(float));
xx = (float *) calloc(ns, sizeof(float));
yy = (float *) calloc(ns, sizeof(float));
// window
for (j = 0; j < nw; j++) ww[j]=0.0f; //clear
for (j = 0; j < nw_orig; j++) {
p = M_PI * (2.0 * j - nw_orig) / nw_orig;
if (wt == 0) {
w = 0.54 + 0.46 * cos(p); // Hamming
} else {
w = (1 - a + cos(p) + a * cos(2 * p)) / 2; // Blackman
}
sm += w;
ww[j] = (float) w;
}
// frequency bands...add the DC-facing band and add the Nyquist-facing band
be[0] = 0;
for (k = 1; k < nc; k++) {
kk = round(nf * cf[k - 1] * (2 / sr));
be[k] = (kk > nf) ? nf : kk;
}
be[nc] = nf;
// channel tranfer functions
fzero(xx, ns);
xx[nw_orig / 2] = 1; //make a single-sample impulse centered on our eventual window
cha_fft_rc(xx, nt);
for (k = 0; k < nc; k++) {
fzero(yy, ns); //zero the temporary output
//int nbins = (be[k + 1] - be[k]) * 2; Serial.print("fir_filterbank: chan ");Serial.print(k); Serial.print(", nbins = ");Serial.println(nbins);
fcopy(yy + be[k] * 2, xx + be[k] * 2, (be[k + 1] - be[k]) * 2); //copy just our passband
cha_fft_cr(yy, nt); //IFFT back into the time domain
// apply window to iFFT of bandpass
for (j = 0; j < nw; j++) {
yy[j] *= ww[j];
}
bk = bb + k * nw_orig; //pointer to location in output array
fcopy(bk, yy, nw_orig); //copy the filter coefficients to the output array
//print out the coefficients
//for (int i=0; i<nw; i++) { Serial.print(yy[i]*1000.0f);Serial.print(" "); }; Serial.println();
}
free(be);
free(ww);
free(xx);
free(yy);
}
void fir_filterbank(float *bb, float *cf, const int nc, const int nw_orig, const int wt, const float sr);
};
#endif

@ -0,0 +1,101 @@
#include "AudioControlTester.h"
void AudioTestSignalGenerator_F32::update(void) {
//receive the input audio data
audio_block_f32_t *in_block = AudioStream_F32::receiveReadOnly_f32();
if (!in_block) return;
//if we're not testing, just transmit the block
if (!is_testing) {
AudioStream_F32::transmit(in_block); // send the FIR output
AudioStream_F32::release(in_block);
return;
}
//if we are testing, we're going to substitute a new signal,
//so we can release the block for the original signal
AudioStream_F32::release(in_block);
//allocate memory for block that we'll send
audio_block_f32_t *out_block = allocate_f32();
if (!out_block) return;
//now generate the new siginal
sine_gen.begin(); record_queue.begin(); //activate
sine_gen.update(); sine_gen.end();
gain_alg.update();
record_queue.update(); record_queue.end();
audio_block_f32_t *queue_block = record_queue.getAudioBlock();
//copy to out_block (why can't I just send the queue_block? I tried. It doesn't seem to work. try it again later!
for (int i=0; i < queue_block->length; i++) out_block->data[i] = queue_block->data[i];
record_queue.freeAudioBlock();
//send the data
AudioStream_F32::transmit(out_block); // send the FIR output
AudioStream_F32::release(out_block);
}
void AudioTestSignalMeasurement_F32::update(void) {
//if we're not testing, just return
if (!is_testing) {
return;
}
//receive the input audio data...the baseline and the test
audio_block_f32_t *in_block_baseline = AudioStream_F32::receiveReadOnly_f32(0);
if (!in_block_baseline) return;
audio_block_f32_t *in_block_test = AudioStream_F32::receiveReadOnly_f32(1);
if (!in_block_test) {
AudioStream_F32::release(in_block_baseline);
return;
}
//compute the rms of both signals
float baseline_rms = computeRMS(in_block_baseline->data, in_block_baseline->length);
float test_rms = computeRMS(in_block_test->data, in_block_test->length);
//Release memory
AudioStream_F32::release(in_block_baseline);
AudioStream_F32::release(in_block_test);
//notify controller
if (testController != NULL) testController->transferRMSValues(baseline_rms, test_rms);
}
void AudioTestSignalMeasurementMulti_F32::update(void) {
//if we're not testing, just return
if (!is_testing) {
return;
}
//receive the input audio data...the baseline and the test
audio_block_f32_t *in_block_baseline = AudioStream_F32::receiveReadOnly_f32(0);
if (in_block_baseline==NULL) return;
float baseline_rms = computeRMS(in_block_baseline->data, in_block_baseline->length);
AudioStream_F32::release(in_block_baseline);
//loop over each of the test data connections
float test_rms[num_test_values];
int n_with_data = 0;
for (int Ichan=0; Ichan < num_test_values; Ichan++) {
audio_block_f32_t *in_block_test = AudioStream_F32::receiveReadOnly_f32(1+Ichan);
if (in_block_test==NULL) {
//no data
test_rms[Ichan]=0.0f;
} else {
//process data
n_with_data = Ichan+1;
test_rms[Ichan]=computeRMS(in_block_test->data, in_block_test->length);
AudioStream_F32::release(in_block_test);
}
}
//notify controller
if (testController != NULL) testController->transferRMSValues(baseline_rms, test_rms, n_with_data);
}

@ -0,0 +1,538 @@
#ifndef _AudioControlTester_h
#define _AudioControlTester_h
//include <Tympan_Library.h>
#include <OpenAudio_ArduinoLibrary.h>
#define max_steps 64
#define max_num_chan 16 //max number of test signal inputs to the AudioTestSignalMeasurementMulti_F32
//prototypes
class AudioTestSignalGenerator_F32;
class AudioTestSignalMeasurementInterface_F32;
class AudioTestSignalMeasurement_F32;
class AudioTestSignalMeasurementMulti_F32;
class AudioControlSignalTesterInterface_F32;
class AudioControlSignalTester_F32;
class AudioControlTestAmpSweep_F32;
class AudioControlTestFreqSweep_F32;
// class definitions
class AudioTestSignalGenerator_F32 : public AudioStream_F32
{
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName: testSignGen
public:
AudioTestSignalGenerator_F32(void): AudioStream_F32(1,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
setDefaultValues();
makeConnections();
}
AudioTestSignalGenerator_F32(const AudioSettings_F32 &settings): AudioStream_F32(1,inputQueueArray) {
setAudioSettings(settings);
setDefaultValues();
makeConnections();
}
~AudioTestSignalGenerator_F32(void) {
if (patchCord1 != NULL) delete patchCord1;
}
void setAudioSettings(const AudioSettings_F32 &settings) {
setSampleRate_Hz(settings.sample_rate_Hz);
}
void setSampleRate_Hz(const float _fs_Hz) {
//pass this data on to its components that care
sine_gen.setSampleRate_Hz(_fs_Hz);
}
void makeConnections(void) {
patchCord1 = new AudioConnection_F32(sine_gen, 0, gain_alg, 0);
patchCord2 = new AudioConnection_F32(gain_alg, 0, record_queue, 0);
}
virtual void update(void);
void begin(void) {
is_testing = true;
//if (Serial) Serial.println("AudioTestSignalGenerator_F32: begin(): ...");
}
void end(void) { is_testing = false; }
AudioSynthWaveformSine_F32 sine_gen;
AudioEffectGain_F32 gain_alg;
AudioRecordQueue_F32 record_queue;
AudioConnection_F32 *patchCord1;
AudioConnection_F32 *patchCord2;
void amplitude(float val) {
sine_gen.amplitude(1.0);
gain_alg.setGain(val);
}
void frequency(float val) {
sine_gen.frequency(val);
}
virtual void setSignalAmplitude_dBFS(float val_dBFS) {
amplitude(sqrtf(2.0)*sqrtf(powf(10.0f,0.1*val_dBFS)));
};
virtual void setSignalFrequency_Hz(float val_Hz) {
frequency(val_Hz);
}
private:
bool is_testing = false;
audio_block_f32_t *inputQueueArray[1];
void setDefaultValues(void) {
sine_gen.end(); //disable it for now
record_queue.end(); //disable it for now;
is_testing = false;
frequency(1000.f);
amplitude(0.0f);
}
};
// //////////////////////////////////////////////////////////////////////////
class AudioTestSignalMeasurementInterface_F32 {
public:
AudioTestSignalMeasurementInterface_F32 (void) {};
void setAudioSettings(const AudioSettings_F32 &settings) {
setSampleRate_Hz(settings.sample_rate_Hz);
}
void setSampleRate_Hz(const float _fs_Hz) {
//pass this data on to its components that care. None care right now.
}
virtual void update(void);
virtual float computeRMS(float data[], int n) {
float rms_value;
arm_rms_f32 (data, n, &rms_value);
return rms_value;
}
virtual void begin(AudioControlSignalTester_F32 *p_controller) {
//if (Serial) Serial.println("AudioTestSignalMeasurement_F32: begin(): ...");
testController = p_controller;
is_testing = true;
}
virtual void end(void) {
//if (Serial) Serial.println("AudioTestSignalMeasurement_F32: end(): ...");
testController = NULL;
is_testing = false;
}
protected:
bool is_testing = false;
//audio_block_f32_t *inputQueueArray[2];
AudioControlSignalTester_F32 *testController = NULL;
virtual void setDefaultValues(void) {
is_testing = false;
}
};
class AudioTestSignalMeasurement_F32 : public AudioStream_F32, public AudioTestSignalMeasurementInterface_F32
{
//GUI: inputs:2, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: testSigMeas
public:
AudioTestSignalMeasurement_F32(void): AudioStream_F32(2,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
setDefaultValues();
}
AudioTestSignalMeasurement_F32(const AudioSettings_F32 &settings): AudioStream_F32(2,inputQueueArray) {
setAudioSettings(settings);
setDefaultValues();
}
void update(void);
private:
audio_block_f32_t *inputQueueArray[2];
};
class AudioTestSignalMeasurementMulti_F32 : public AudioStream_F32, public AudioTestSignalMeasurementInterface_F32
{
//GUI: inputs:10, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: testSigMeas
public:
AudioTestSignalMeasurementMulti_F32(void): AudioStream_F32(max_num_chan+1,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
setDefaultValues();
}
AudioTestSignalMeasurementMulti_F32(const AudioSettings_F32 &settings): AudioStream_F32(max_num_chan+1,inputQueueArray) {
setAudioSettings(settings);
setDefaultValues();
}
void update(void);
private:
//int num_input_connections = max_num_chan+1;
int num_test_values = max_num_chan;
audio_block_f32_t *inputQueueArray[max_num_chan+1];
};
// ///////////////////////////////////////////////////////////////////////////////////
class AudioControlSignalTesterInterface_F32 {
public:
AudioControlSignalTesterInterface_F32(void) {};
//virtual void setAudioBlockSamples(void) = 0;
//virtual void setSampleRate_hz(void) = 0;
virtual void begin(void) = 0;
virtual void end(void) = 0;
virtual void setStepPattern(float, float, float) = 0;
virtual void transferRMSValues(float, float) = 0;
virtual void transferRMSValues(float, float *, int) = 0;
virtual bool available(void) = 0;
};
class AudioControlSignalTester_F32 : public AudioControlSignalTesterInterface_F32
{
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: sigTest(Abstract)
public:
AudioControlSignalTester_F32(AudioSettings_F32 &settings, AudioTestSignalGenerator_F32 &_sig_gen, AudioTestSignalMeasurementInterface_F32 &_sig_meas)
: AudioControlSignalTesterInterface_F32(), sig_gen(_sig_gen), sig_meas(_sig_meas) {
setAudioBlockSamples(settings.audio_block_samples);
setSampleRate_Hz(settings.sample_rate_Hz);
resetState();
}
virtual void begin(void) {
Serial.println("AudioControlSignalTester_F32: begin(): ...");
recomputeTargetCountsPerStep(); //not needed, just to print some debugging messages
//activate the instrumentation
sig_gen.begin();
sig_meas.begin(this);
//start the test
resetState();
gotoNextStep();
}
//use this to cancel the test
virtual void end(void) {
finishTest();
}
void setAudioSettings(AudioSettings_F32 audio_settings) {
setAudioBlockSamples(audio_settings.audio_block_samples);
setSampleRate_Hz(audio_settings.sample_rate_Hz);
}
void setAudioBlockSamples(int block_samples) {
audio_block_samples = block_samples;
recomputeTargetCountsPerStep();
}
void setSampleRate_Hz(float fs_Hz) {
sample_rate_Hz = fs_Hz;
recomputeTargetCountsPerStep();
}
//define how long (seconds) to spend at each step of the test
void setTargetDurPerStep_sec(float sec) {
if (sec > 0.001) {
target_dur_per_step_sec = sec;
recomputeTargetCountsPerStep();
} else {
Serial.print(F("AudioControlSignalTester_F32: setTargetDurPerStep_sec: given duration too short: "));
Serial.print(target_dur_per_step_sec);
Serial.print(F(". Ignoring..."));
return;
}
}
virtual void setStepPattern(float _start_val, float _end_val, float _step_val) {
start_val = _start_val; end_val = _end_val; step_val = _step_val;
recomputeTargetNumberOfSteps();
}
virtual void transferRMSValues(float baseline_rms, float test_rms) {
transferRMSValues(baseline_rms, &test_rms, 1);
}
virtual void transferRMSValues(float baseline_rms, float *test_rms, int num_chan) {
if (counter_ignore > 0) {
//ignore this reading
counter_ignore--;
return;
}
given_num_chan = num_chan;
if (given_num_chan > max_num_chan) {
Serial.println(F("AudioControlSignalTester_F32: transferRMSValues: *** ERROR ***"));
Serial.print(F(" : num_chan (")); Serial.print(num_chan); Serial.print(")");
Serial.print(F(" is bigger max_num_chan (")); Serial.println(max_num_chan);
Serial.println(F(" : Skipping..."));
return;
}
//add this number
sum_sig_pow_baseline[counter_step] += (baseline_rms*baseline_rms);
for (int Ichan=0; Ichan < num_chan; Ichan++) {
sum_sig_pow_test[counter_step][Ichan] += (test_rms[Ichan]*test_rms[Ichan]);
}
freq_at_each_step_Hz[counter_step] = signal_frequency_Hz;
counter_sum[counter_step]++;
//have all the channels checked in?
if (counter_sum[counter_step] >= target_counts_per_step) {
gotoNextStep();
}
}
virtual void setSignalFrequency_Hz(float freq_Hz) {
signal_frequency_Hz = freq_Hz;
sig_gen.setSignalFrequency_Hz(signal_frequency_Hz);
}
virtual void setSignalAmplitude_dBFS(float amp_dBFS) {
signal_amplitude_dBFS = amp_dBFS;
sig_gen.setSignalAmplitude_dBFS(amp_dBFS);
}
virtual void printTableOfResults(Stream *s) {
float ave1_dBFS, ave2_dBFS, ave3_dBFS, gain_dB, total_pow, total_wav, foo_pow;
s->println(" : Freq (Hz), Input (dBFS), Per-Chan Output (dBFS), Total Gain (inc) (dB), Total Gain (coh) (dB)");
//s->print(" : given_num_chan = ");s->println(given_num_chan);
for (int i=0; i < target_n_steps; i++) {
ave1_dBFS = 10.f*log10f(sum_sig_pow_baseline[i]/counter_sum[i]);
s->print(" "); s->print(freq_at_each_step_Hz[i],0);
s->print(", "); s->print(ave1_dBFS,1);
total_pow = 0.0f;
total_wav = 0.0f;
for (int Ichan=0; Ichan < given_num_chan; Ichan++) {
if (Ichan==0) {
s->print(", ");
} else {
s->print(", ");
}
foo_pow = sum_sig_pow_test[i][Ichan]/counter_sum[i];
ave2_dBFS = 10.f*log10f(foo_pow);
s->print(ave2_dBFS,1);
total_pow += foo_pow; //sum as if it's noise being recombined incoherently
total_wav += sqrtf(foo_pow); //sum as it it's a in-phase tone being combined coherently
}
ave2_dBFS = 10.f*log10f(total_pow);
gain_dB = ave2_dBFS - ave1_dBFS;
s->print(", "); s->print(gain_dB,2);
ave3_dBFS = 20.f*log10f(total_wav);
gain_dB = ave3_dBFS - ave1_dBFS;
s->print(", "); s->println(gain_dB,2);
}
}
bool isDataAvailable = false;
bool available(void) { return isDataAvailable; }
protected:
AudioTestSignalGenerator_F32 &sig_gen;
AudioTestSignalMeasurementInterface_F32 &sig_meas;
float signal_frequency_Hz = 1000.f;
float signal_amplitude_dBFS = -50.0f;
int counter_ignore = 0;
//bool is_testing = 0;
int audio_block_samples = AUDIO_BLOCK_SAMPLES;
float sample_rate_Hz = AUDIO_SAMPLE_RATE_EXACT;
float target_dur_per_step_sec = 0.2;
int target_counts_per_step = 1;
//const int max_steps = 64;
float start_val = 0, end_val = 1.f, step_val = 1.f;
int target_n_steps = 1;
int given_num_chan = max_num_chan;
float sum_sig_pow_baseline[max_steps];
float sum_sig_pow_test[max_steps][max_num_chan];
float freq_at_each_step_Hz[max_steps];
int counter_sum[max_steps], counter_step=-1;
int recomputeTargetCountsPerStep(void) {
target_counts_per_step = max(1,(int)((target_dur_per_step_sec * sample_rate_Hz / ((float)audio_block_samples))+0.5)); //round
// if (Serial) {
// Serial.println("AudioControlSignalTester_F32: recomputeTargetCountsPerStep: ");
// Serial.print(" : target_dur_per_step_sec = "); Serial.println(target_dur_per_step_sec);
// Serial.print(" : sample_rate_Hz = "); Serial.println(sample_rate_Hz);
// Serial.print(" : audio_block_samples = "); Serial.println(audio_block_samples);
// Serial.print(" : target_counts_per_step = "); Serial.println(target_counts_per_step);
// }
return target_counts_per_step;
}
virtual int recomputeTargetNumberOfSteps(void) {
return target_n_steps = (int)((end_val - start_val)/step_val + 0.5)+1; //round
}
virtual void resetState(void) {
isDataAvailable = false;
for (int i=0; i<max_steps; i++) {
sum_sig_pow_baseline[i]=0.0f;
for (int Ichan=0; Ichan<max_num_chan; Ichan++) sum_sig_pow_test[i][Ichan]=0.0f;
counter_sum[i] = 0;
}
counter_step = -1;
}
virtual void gotoNextStep(void) {
counter_step++;
//Serial.print("AudioControlSignalTester_F32: gotoNextStep: starting step ");
//Serial.println(counter_step);
if (counter_step >= target_n_steps) {
finishTest();
return;
} else {
counter_ignore = 10; //ignore first 10 packets
counter_sum[counter_step]=0;
sum_sig_pow_baseline[counter_step]=0.0f;
for (int Ichan=0; Ichan < max_num_chan; Ichan++) sum_sig_pow_test[counter_step][Ichan]=0.0f;
updateSignalGenerator();
freq_at_each_step_Hz[counter_step]=0.0f;
}
}
virtual void updateSignalGenerator(void)
{
//if (Serial) Serial.println("AudioControlSignalTester_F32: updateSignalGenerator(): did the child version get called?");
} //override this is a child class!
virtual void finishTest(void) {
//Serial.println("AudioControlSignalTester_F32: finishTest()...");
//disable the test instrumentation
sig_gen.end();
sig_meas.end();
//let listeners know that data is available
isDataAvailable = true;
}
};
// //////////////////////////////////////////////////////////////////////////
class AudioControlTestAmpSweep_F32 : public AudioControlSignalTester_F32
{
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: ampSweepTester
public:
AudioControlTestAmpSweep_F32(AudioSettings_F32 &settings, AudioTestSignalGenerator_F32 &_sig_gen, AudioTestSignalMeasurementInterface_F32 &_sig_meas)
: AudioControlSignalTester_F32(settings, _sig_gen,_sig_meas)
{
float start_amp_dB = -100.0f, end_amp_dB = 0.0f, step_amp_dB = 2.5f;
setStepPattern(start_amp_dB, end_amp_dB, step_amp_dB);
setTargetDurPerStep_sec(0.25);
resetState();
}
void begin(void) {
//activate the instrumentation
sig_gen.begin();
sig_meas.begin(this);
//start the test
resetState();
gotoNextStep();
}
//use this to cancel the test
//void end(void) {
// finishTest();
//}
void printTableOfResults(Stream *s) {
s->println("AudioControlTestAmpSweep_F32: Start Table of Results...");
AudioControlSignalTester_F32::printTableOfResults(s);
s->println("AudioControlTestAmpSweep_F32: End Table of Results...");
}
protected:
virtual void updateSignalGenerator(void) {
float new_amp_dB = start_val + ((float)counter_step)*step_val; //start_val and step_val are in parent class
Serial.print("AudioControlTestAmpSweep_F32: updateSignalGenerator(): setting amplitude to (dBFS) ");
Serial.println(new_amp_dB);
setSignalAmplitude_dBFS(new_amp_dB);
}
void finishTest(void) {
//disable the test instrumentation
setSignalAmplitude_dBFS(-1000.0f); //some very quiet value
//do all of the common actions
AudioControlSignalTester_F32::finishTest();
//print results
printTableOfResults(&Serial);
}
//void resetState(void) {
// AudioControlSignalTester_F32::resetState();
//}
};
// //////////////////////////////////////////////////////////////////////////
class AudioControlTestFreqSweep_F32 : public AudioControlSignalTester_F32
{
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: freqSweepTester
public:
AudioControlTestFreqSweep_F32(AudioSettings_F32 &settings, AudioTestSignalGenerator_F32 &_sig_gen, AudioTestSignalMeasurementInterface_F32 &_sig_meas)
: AudioControlSignalTester_F32(settings, _sig_gen,_sig_meas)
{
float start_freq_Hz = 125.f, end_freq_Hz = 16000.f, step_freq_octave = sqrtf(2.0);
setStepPattern(start_freq_Hz, end_freq_Hz, step_freq_octave);
setTargetDurPerStep_sec(0.25);
resetState();
}
void begin(void) {
//activate the instrumentation
sig_gen.begin();
sig_meas.begin(this);
//start the test
resetState();
recomputeTargetNumberOfSteps();
gotoNextStep();
}
//use this to cancel the test
//void end(void) {
// finishTest();
//}
void printTableOfResults(Stream *s) {
s->println("AudioControlTestFreqSweep_F32: Start Table of Results...");
AudioControlSignalTester_F32::printTableOfResults(s);
s->println("AudioControlTestFreqSweep_F32: End Table of Results...");
}
protected:
float signal_frequency_Hz = 1000.f;
float signal_amplitude_dBFS = -50.0f;
virtual int recomputeTargetNumberOfSteps(void) {
return target_n_steps = (int)(log10f(end_val/start_val)/log10f(step_val)+0.5) + 1; //round
}
virtual void updateSignalGenerator(void) {
//logarithmically step the frequency
float new_freq_Hz = start_val * powf(step_val,counter_step);
Serial.print("AudioControlTestFreqSweep_F32: updateSignalGenerator(): setting freq to ");
Serial.println(new_freq_Hz);
setSignalFrequency_Hz(new_freq_Hz);
}
void finishTest(void) {
//disable the test instrumentation
setSignalAmplitude_dBFS(-1000.0f); //some very quiet value
setSignalFrequency_Hz(1000.f);
//do all of the common actions
AudioControlSignalTester_F32::finishTest();
//print results
printTableOfResults(&Serial);
}
//void resetState(void) {
// AudioControlSignalTester_F32::resetState();
//}
};
#endif

@ -9,6 +9,8 @@ class AudioConvert_I16toF32 : public AudioStream_F32 //receive Int and transmits
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
public:
AudioConvert_I16toF32(void) : AudioStream_F32(1, inputQueueArray_f32) { };
AudioConvert_I16toF32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32) { };
void update(void) {
//get the Int16 block
audio_block_t *int_block;

@ -12,150 +12,21 @@
#ifndef _AudioEffectCompWDRC_F32
#define _AudioEffectCompWDRC_F32
class AudioCalcGainWDRC_F32; //forward declared. Actually defined in later header file, but I need this here to avoid circularity
#include <Arduino.h>
#include <AudioStream_F32.h>
#include <arm_math.h>
#include <AudioCalcEnvelope_F32.h>
#include "AudioCalcGainWDRC_F32.h" //has definition of CHA_WDRC
#include "utility/textAndStringUtils.h"
// from CHAPRO cha_ff.h
#define DSL_MXCH 32
//class CHA_DSL {
typedef struct {
//public:
//CHA_DSL(void) {};
//static const int DSL_MXCH = 32; // maximum number of channels
float attack; // attack time (ms)
float release; // release time (ms)
float maxdB; // maximum signal (dB SPL)
int ear; // 0=left, 1=right
int nchannel; // number of channels
float cross_freq[DSL_MXCH]; // cross frequencies (Hz)
float tkgain[DSL_MXCH]; // compression-start gain
float cr[DSL_MXCH]; // compression ratio
float tk[DSL_MXCH]; // compression-start kneepoint
float bolt[DSL_MXCH]; // broadband output limiting threshold
} CHA_DSL;
/* int parseStringIntoDSL(String &text_buffer) {
int position = 0;
float foo_val;
const bool print_debug = false;
if (print_debug) Serial.println("parseTextAsDSL: values from file:");
position = parseNextNumberFromString(text_buffer, position, foo_val);
attack = foo_val;
if (print_debug) { Serial.print(" attack: "); Serial.println(attack); }
position = parseNextNumberFromString(text_buffer, position, foo_val);
release = foo_val;
if (print_debug) { Serial.print(" release: "); Serial.println(release); }
position = parseNextNumberFromString(text_buffer, position, foo_val);
maxdB = foo_val;
if (print_debug) { Serial.print(" maxdB: "); Serial.println(maxdB); }
position = parseNextNumberFromString(text_buffer, position, foo_val);
ear = int(foo_val + 0.5); //round
if (print_debug) { Serial.print(" ear: "); Serial.println(ear); }
position = parseNextNumberFromString(text_buffer, position, foo_val);
nchannel = int(foo_val + 0.5); //round
if (print_debug) { Serial.print(" nchannel: "); Serial.println(nchannel); }
//check to see if the number of channels is acceptable.
if ((nchannel < 0) || (nchannel > DSL_MXCH)) {
if (print_debug) Serial.print(" : channel number is too big (or negative). stopping.");
return -1;
}
//read the cross-over frequencies. There should be nchan-1 of them (0 and Nyquist are assumed)
if (print_debug) Serial.print(" cross_freq: ");
for (int i=0; i < (nchannel-1); i++) {
position = parseNextNumberFromString(text_buffer, position, foo_val);
cross_freq[i] = foo_val;
if (print_debug) { Serial.print(cross_freq[i]); Serial.print(", ");}
}
if (print_debug) Serial.println();
//read the tkgain values. There should be nchan of them
if (print_debug) Serial.print(" tkgain: ");
for (int i=0; i < nchannel; i++) {
position = parseNextNumberFromString(text_buffer, position, foo_val);
tkgain[i] = foo_val;
if (print_debug) { Serial.print(tkgain[i]); Serial.print(", ");}
}
if (print_debug) Serial.println();
//read the cr values. There should be nchan of them
if (print_debug) Serial.print(" cr: ");
for (int i=0; i < nchannel; i++) {
position = parseNextNumberFromString(text_buffer, position, foo_val);
cr[i] = foo_val;
if (print_debug) { Serial.print(cr[i]); Serial.print(", ");}
}
if (print_debug) Serial.println();
//read the tk values. There should be nchan of them
if (print_debug) Serial.print(" tk: ");
for (int i=0; i < nchannel; i++) {
position = parseNextNumberFromString(text_buffer, position, foo_val);
tk[i] = foo_val;
if (print_debug) { Serial.print(tk[i]); Serial.print(", ");}
}
if (print_debug) Serial.println();
//read the bolt values. There should be nchan of them
if (print_debug) Serial.print(" bolt: ");
for (int i=0; i < nchannel; i++) {
position = parseNextNumberFromString(text_buffer, position, foo_val);
bolt[i] = foo_val;
if (print_debug) { Serial.print(bolt[i]); Serial.print(", ");}
}
if (print_debug) Serial.println();
return 0;
}
void printToStream(Stream *s) {
s->print("CHA_DSL: attack (ms) = "); s->println(attack);
s->print(" : release (ms) = "); s->println(release);
s->print(" : maxdB (dB SPL) = "); s->println(maxdB);
s->print(" : ear (0 = left, 1 = right) "); s->println(ear);
s->print(" : nchannel = "); s->println(nchannel);
s->print(" : cross_freq (Hz) = ");
for (int i=0; i<nchannel-1;i++) { s->print(cross_freq[i]); s->print(", ");}; s->println();
s->print(" : tkgain = ");
for (int i=0; i<nchannel;i++) { s->print(tkgain[i]); s->print(", ");}; s->println();
s->print(" : cr = ");
for (int i=0; i<nchannel;i++) { s->print(cr[i]); s->print(", ");}; s->println();
s->print(" : tk = ");
for (int i=0; i<nchannel;i++) { s->print(tk[i]); s->print(", ");}; s->println();
s->print(" : bolt = ");
for (int i=0; i<nchannel;i++) { s->print(bolt[i]); s->print(", ");}; s->println();
}
} ; */
typedef struct {
float alfa; // attack constant (not time)
float beta; // release constant (not time
float fs; // sampling rate (Hz)
float maxdB; // maximum signal (dB SPL)
float tkgain; // compression-start gain
float tk; // compression-start kneepoint
float cr; // compression ratio
float bolt; // broadband output limiting threshold
} CHA_DVAR_t;
#include <AudioCalcGainWDRC_F32.h> //has definition of CHA_WDRC
#include "BTNRH_WDRC_Types.h"
//#include "utility/textAndStringUtils.h"
class AudioEffectCompWDRC_F32 : public AudioStream_F32
{
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName: CompWDRC
//GUI: shortName: CompressWDRC
public:
AudioEffectCompWDRC_F32(void): AudioStream_F32(1,inputQueueArray) { //need to modify this for user to set sample rate
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
@ -178,7 +49,7 @@ class AudioEffectCompWDRC_F32 : public AudioStream_F32
if (!out_block) return;
//do the algorithm
cha_agc_channel(block->data, out_block->data, block->length);
compress(block->data, out_block->data, block->length);
// transmit the block and release memory
AudioStream_F32::transmit(out_block); // send the FIR output
@ -188,11 +59,11 @@ class AudioEffectCompWDRC_F32 : public AudioStream_F32
//here is the function that does all the work
void cha_agc_channel(float *input, float *output, int cs) {
//compress(input, output, cs, &prev_env,
// CHA_DVAR.alfa, CHA_DVAR.beta, CHA_DVAR.tkgain, CHA_DVAR.tk, CHA_DVAR.cr, CHA_DVAR.bolt, CHA_DVAR.maxdB);
compress(input, output, cs);
}
//void cha_agc_channel(float *input, float *output, int cs) {
// //compress(input, output, cs, &prev_env,
// // CHA_DVAR.alfa, CHA_DVAR.beta, CHA_DVAR.tkgain, CHA_DVAR.tk, CHA_DVAR.cr, CHA_DVAR.bolt, CHA_DVAR.maxdB);
// compress(input, output, cs);
//}
//void compress(float *x, float *y, int n, float *prev_env,
// float &alfa, float &beta, float &tkgn, float &tk, float &cr, float &bolt, float &mxdB)
@ -222,23 +93,23 @@ class AudioEffectCompWDRC_F32 : public AudioStream_F32
void setDefaultValues(void) {
//set default values...taken from CHAPRO, GHA_Demo.c from "amplify()"...ignores given sample rate
//assumes that the sample rate has already been set!!!!
CHA_WDRC gha = {1.0f, // attack time (ms)
//set default values...configure as limitter
BTNRH_WDRC::CHA_WDRC gha = {
5.0f, // attack time (ms)
50.0f, // release time (ms)
24000.0f, // fs, sampling rate (Hz), THIS IS IGNORED!
119.0f, // maxdB, maximum signal (dB SPL)
0.0f, // tkgain, compression-start gain
105.0f, // tk, compression-start kneepoint
10.0f, // cr, compression ratio
105.0f // bolt, broadband output limiting threshold
115.0f, // maxdB, maximum signal (dB SPL)...assumed SPL for full-scale input signal
0.0f, // tkgain, compression-start gain (dB)
55.0f, // tk, compression-start kneepoint (dB SPL)
1.0f, // cr, compression ratio (set to 1.0 to defeat)
100.0f // bolt, broadband output limiting threshold (ie, the limiter. SPL. 10:1 comp ratio)
};
setParams_from_CHA_WDRC(&gha);
}
//set all of the parameters for the compressor using the CHA_WDRC structure
//assumes that the sample rate has already been set!!!
void setParams_from_CHA_WDRC(CHA_WDRC *gha) {
void setParams_from_CHA_WDRC(BTNRH_WDRC::CHA_WDRC *gha) {
//configure the envelope calculator...assumes that the sample rate has already been set!
calcEnvelope.setAttackRelease_msec(gha->attack,gha->release); //these are in milliseconds
@ -262,9 +133,25 @@ class AudioEffectCompWDRC_F32 : public AudioStream_F32
given_sample_rate_Hz = _fs_Hz;
calcEnvelope.setSampleRate_Hz(_fs_Hz);
}
void setAttackRelease_msec(const float atk_msec, const float rel_msec) {
calcEnvelope.setAttackRelease_msec(atk_msec, rel_msec);
}
void setKneeLimiter_dBSPL(float _bolt) { calcGain.setKneeLimiter_dBSPL(_bolt); }
void setKneeLimiter_dBFS(float _bolt_dBFS) { calcGain.setKneeLimiter_dBFS(_bolt_dBFS); }
void setGain_dB(float _gain_dB) { calcGain.setGain_dB(_gain_dB); } //gain at start of compression
void setKneeCompressor_dBSPL(float _tk) { calcGain.setKneeCompressor_dBSPL(_tk); }
void setKneeCompressor_dBFS(float _tk_dBFS) { calcGain.setKneeCompressor_dBFS(_tk_dBFS); }
void setCompRatio(float _cr) { calcGain.setCompRatio(_cr); }
void setMaxdB(float _maxdB) { calcGain.setMaxdB(_maxdB); };
float getCurrentLevel_dB(void) { return AudioCalcGainWDRC_F32::db2(calcEnvelope.getCurrentLevel()); } //this is 20*log10(abs(signal)) after the envelope smoothing
float getGain_dB(void) { return calcGain.getGain_dB(); } //returns the linear gain of the system
float getCurrentGain(void) { return calcGain.getCurrentGain(); }
float getCurrentGain_dB(void) { return calcGain.getCurrentGain_dB(); }
AudioCalcEnvelope_F32 calcEnvelope;
AudioCalcGainWDRC_F32 calcGain;

@ -22,13 +22,20 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
public:
//constructor
AudioEffectCompressor_F32(void) : AudioStream_F32(1, inputQueueArray_f32) {
setDefaultValues(AUDIO_SAMPLE_RATE); resetStates();
};
AudioEffectCompressor_F32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32) {
setDefaultValues(settings.sample_rate_Hz); resetStates();
};
void setDefaultValues(const float sample_rate_Hz) {
setThresh_dBFS(-20.0f); //set the default value for the threshold for compression
setCompressionRatio(5.0f); //set the default copression ratio
setAttack_sec(0.005f, AUDIO_SAMPLE_RATE); //default to this value
setRelease_sec(0.200f, AUDIO_SAMPLE_RATE); //default to this value
setHPFilterCoeff(); enableHPFilter(true); //enable the HP filter to remove any DC offset from the audio
resetStates();
};
setAttack_sec(0.005f, sample_rate_Hz); //default to this value
setRelease_sec(0.200f, sample_rate_Hz); //default to this value
setHPFilterCoeff(); enableHPFilter(true); //enable the HP filter to remove any DC offset from the audio
}
//here's the method that does all the work
void update(void) {
@ -133,7 +140,7 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
inst_targ_gain_dB_block->data, //this is the output
above_thresh_dB_block->length);