<commit_before>/*
 * AudioCalcGainWDRC_F32
 * 
 * Created: <NAME>, Feb 2017
 * Purpose: This module calculates the gain needed for wide dynamic range compression.
 * Derived From: Core algorithm is from "WDRC_circuit"
 *     WDRC_circuit from CHAPRO from BTNRC: https://github.com/BTNRH/chapro
 *     As of Feb 2017, CHAPRO license is listed as "Creative Commons?"
 *          
 * This processes a single stream fo audio data (ie, it is mono)       
 *          
 * MIT License.  use at your own risk.
*/

#ifndef _AudioCalcGainWDRC_F32_h
#define _AudioCalcGainWDRC_F32_h

#include <arm_math.h> //ARM DSP extensions.  for speed!
#include <AudioStream_F32.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
{
  //GUI: inputs:1, outputs:1  //this line used for automatic generation of GUI node
  //GUI: shortName:calc_WDRCGain
  public:
    //default constructor
    AudioCalcGainWDRC_F32(void) : AudioStream_F32(1, inputQueueArray_f32) { setDefaultValues(); };

    //here's the method that does all the work
    void update(void) {
      
      //get the input audio data block
      audio_block_f32_t *in_block = AudioStream_F32::receiveReadOnly_f32(); // must be the envelope!
      if (!in_block) return;
  
      //prepare an output data block
      audio_block_f32_t *out_block = AudioStream_F32::allocate_f32();
      if (!out_block) return;
      
      // //////////////////////add your 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;
      
      //transmit the block and be done
      AudioStream_F32::transmit(out_block);
      AudioStream_F32::release(out_block);
      AudioStream_F32::release(in_block);
      
    }
  
    void calcGainFromEnvelope(float *env, float *gain_out, const int n)  {
      //env = input, signal envelope (not the envelope of the power, but the envelope of the signal itslef)
      //gain = output, the gain in natural units (not power, not dB)
      //n = input, number of samples to process in each vector
  
      //prepare intermediate data block
      audio_block_f32_t *env_dB_block = AudioStream_F32::allocate_f32();
      if (!env_dB_block) return;
  
      //convert to dB
      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
      WDRC_circuit_gain(env_dB_block->data, gain_out, n, tkgn, tk, cr, bolt);
      AudioStream_F32::release(env_dB_block);
    }

    //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
    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) {
      
      float gdb, tkgo, pblt;
      int k;
      float *pdb = env_dB; //just rename it to keep the code below unchanged
      float tk_tmp = tk;
      
      if ((tk_tmp + tkgn) > bolt) {
          tk_tmp = bolt - tkgn;
      }
      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];
        } else {
            gdb = cr_const * pdb[k] + tkgo;
        }
        gain_out[k] = undb2(gdb);
        //y[k] = x[k] * undb2(gdb); //apply the gain
      }
    }
    
    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
      };
      //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) {
      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) {
      maxdB = _maxdB;
      tkgn = _tkgain;
      tk = _tk;
      cr = _cr;<commit_msg>AudioCalcGainWDRC: comments to figure out what's happening<commit_after>/*
 * AudioCalcGainWDRC_F32
 * 
 * Created: <NAME>, Feb 2017
 * Purpose: This module calculates the gain needed for wide dynamic range compression.
 * Derived From: Core algorithm is from "WDRC_circuit"
 *     WDRC_circuit from CHAPRO from BTNRC: https://github.com/BTNRH/chapro
 *     As of Feb 2017, CHAPRO license is listed as "Creative Commons?"
 *          
 * This processes a single stream fo audio data (ie, it is mono)       
 *          
 * MIT License.  use at your own risk.
*/

#ifndef _AudioCalcGainWDRC_F32_h
#define _AudioCalcGainWDRC_F32_h

#include <arm_math.h> //ARM DSP extensions.  for speed!
#include <AudioStream_F32.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
{
  //GUI: inputs:1, outputs:1  //this line used for automatic generation of GUI node
  //GUI: shortName:calc_WDRCGain
  public:
    //default constructor
    AudioCalcGainWDRC_F32(void) : AudioStream_F32(1, inputQueueArray_f32) { setDefaultValues(); };

    //here's the method that does all the work
    void update(void) {
      
      //get the input audio data block
      audio_block_f32_t *in_block = AudioStream_F32::receiveReadOnly_f32(); // must be the envelope!
      if (!in_block) return;
  
      //prepare an output data block
      audio_block_f32_t *out_block = AudioStream_F32::allocate_f32();
      if (!out_block) return;
      
      // ////////////////////// 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;
      
      //transmit the block and be done
      AudioStream_F32::transmit(out_block);
      AudioStream_F32::release(out_block);
      AudioStream_F32::release(in_block);
      
    }
  
    void calcGainFromEnvelope(float *env, float *gain_out, const int n)  {
      //env = input, signal envelope (not the envelope of the power, but the envelope of the signal itslef)
      //gain = output, the gain in natural units (not power, not dB)
      //n = input, number of samples to process in each vector
  
      //prepare intermediate data block
      audio_block_f32_t *env_dB_block = AudioStream_F32::allocate_f32();
      if (!env_dB_block) return;
  
      //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
      WDRC_circuit_gain(env_dB_block->data, gain_out, n, tkgn, tk, cr, bolt);
      AudioStream_F32::release(env_dB_block);
    }

    //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 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) 
    	//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 (input SPL dB)
      float tk_tmp = tk;   //temporary, threshold for start of compression (input SPL dB)
      
      // (50 + 30) = 80;  80 ?> 100.  No.  tk_tmp stays at 50
      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 = 30 + 50*(1-1/3) = 30 + 50*0.666 = 30+33.3 = 63.333;
      tkgo = tkgn + tk_tmp * (1.0f - 1.0f / cr);  //intermediate calc
      //pblt = 2 * (100 - 63.3333) = 2*(36.666) = 73.3333;
      pblt = cr * (bolt - tkgo); //calc input level (dB) where we need to start limiting, no just compression
      //cr_cosnt = ((1/3)-1) = -0.6666
      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
        	//assume pdb is 73.3333; gdb = 100 + ((73.333-73.333)/10) - 73.333 = 26.6667.  So, output would be 100 dB
        	//assume pdb is 80 dB SPL input: gdb = 100 + ((80-73.33)/10)-80 = 100+((6.666/10)-80 = 20 + 0.666 = 20.6666;  So, output would be 100.666
            gdb = bolt + ((pdb[k] - pblt) / 10.0f) - pdb[k]; //10:1 limiting!
        } else {
        	//assume pdb = 50; gdb = -0.6666*60+63.333 = -40+63.333 = 23.333.  So, output would be 73.333 (should be 80?)
        	//assume pdb = 73.3333; gcb = -0.6666*73.333 + 63.3333 = -48.8888+63.333 = 14.44444 gain.  So, output would be 87.7778 (shoud be 100)
            gdb = cr_const * pdb[k] + tkgo; 
            
            //assume pdb = 50; gdb = 30 - (50-50)/3 = 30
            //assume pdb = 73.333; gdb = 30 - (73.333-50)/3 = 30 - 7.777 = 22.333
            gdb = tkgn - (pdb[k]-tk)/cr; //WEA thinks it should be this??
        }
        gain_out[k] = undb2(gdb);
        //y[k] = x[k] * undb2(gdb); //apply the gain
      }
    }
    
    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
      };
      //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) {
      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) {
      maxdB = _maxdB;
      tkgn = _tkgain;
      tk = _tk;
      cr = _cr;
{'fraction_non_alphanumeric': 0.11630827185685136, 'fraction_numerical': 0.03790613718411552, 'mean_word_length': 2.280895983522142, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 44, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4589540', 'n_tokens_mistral': 4751, 'n_tokens_neox': 4299, 'n_words': 1344}