//
// Created by Michael Specter on 6/15/20.
//
#include "RandomNoise.h"
#include "Logging.h"

// highpass filter taps
const float b[] = {
    -0.000236437942135332, 0.000815325587435857, -0.00183656749123850, 0.00322373502187833,
    -0.00457968516861099,  0.00537189644388272, -0.00505499229413463,0.00347779908067731,
    -0.000994138199842880,-0.00149735453578532,0.00299215894167622,-0.00281888001320860,
     0.00112282019378742,  0.00117742109999269,-0.00276190993327034,0.00268673229611326,
    -0.000919027237732912,-0.00151847017808169,0.00313502230989920,-0.00282316058926014,
     0.000639139330387021,0.00216118221188974,-0.00378479893826083,0.00305407445743594,
    -0.000213098251323078,-0.00305509803583764,0.00462083414717519,-0.00325156533384849,
    -0.000442882872856017,0.00423976399299556,-0.00559353103863132,0.00332987943691472,
     0.00143089652234904,-0.00575220869787921,0.00667203811847967,-0.00318132338188699,
    -0.00285718529266932,0.00765172352815033,-0.00780739875056750,0.00268031096794725,
     0.00487600364443114,-0.0100153958122534,0.00895157284903807,-0.00164111991850756,
    -0.00771526406578997,0.0129957257493104,-0.0100525527756791,-0.000208683315191778,
     0.0117728338217874,-0.0168823062953845,0.0110573662379157,0.00338991198315377,
    -0.0178761268941901,0.0223633756310119,-0.0118999586500315,-0.00913092301919785,
     0.0282155195419526,-0.0314611418824086,0.0125464824690390,0.0213641817308486,
    -0.0508192925894373,0.0527952804647337,-0.0129465536996555,-0.0650313835263956,
     0.158401873393614,-0.234059009950929,0.263085660805954,-0.234059009950929,
     0.158401873393614,-0.0650313835263956,-0.0129465536996555,0.0527952804647337,
    -0.0508192925894373,0.0213641817308486,0.0125464824690390,-0.0314611418824086,
     0.0282155195419526,-0.00913092301919785,-0.0118999586500315,0.0223633756310119,
    -0.0178761268941901,0.00338991198315377,0.0110573662379157,-0.0168823062953845,
     0.0117728338217874,-0.000208683315191778,-0.0100525527756791,0.0129957257493104,
    -0.00771526406578997,-0.00164111991850756,0.00895157284903807,-0.0100153958122534,
     0.00487600364443114,0.00268031096794725,-0.00780739875056750,0.00765172352815033,
    -0.00285718529266932,-0.00318132338188699,0.00667203811847967,-0.00575220869787921,
     0.00143089652234904,0.00332987943691472,-0.00559353103863132,0.00423976399299556,
    -0.000442882872856017,-0.00325156533384849,0.00462083414717519,-0.00305509803583764,
    -0.000213098251323078,0.00305407445743594,-0.00378479893826083,0.00216118221188974,
     0.000639139330387021,-0.00282316058926014,0.00313502230989920,-0.00151847017808169,
    -0.000919027237732912,0.00268673229611326,-0.00276190993327034,0.00117742109999269,
     0.00112282019378742,-0.00281888001320860,0.00299215894167622,-0.00149735453578532,
    -0.000994138199842880,0.00347779908067731,-0.00505499229413463,0.00537189644388272,
    -0.00457968516861099,0.00322373502187833,-0.00183656749123850,0.000815325587435857,
    -0.00023643794213533};

const float lowpass[] = {
    -0.00035660257342508164,0.00021915832706412156,3.203029953990867e-18,-0.00023780079514758846,
    0.00041905437859361927,-0.0004759863462209164,0.0003701519931112516,-0.00011087499350943243,
    -0.00023731427604140908,0.0005647008660650613,-0.0007456859602351443,0.0006817997752530303,
    -0.00034532399164459286,-0.00019375049084193195,0.0007725693980961322,-0.0011779605890982871,
    0.001218460587898806,-0.0008035635123015404,1.3192743492214573e-17,0.0009622870909900475,
    -0.0017471076611631088,0.002021774776547739,-0.0015864160501667145,0.0004756319450753634,
    0.0010123384560741626,-0.0023831615108438763,0.0031011650776205674,-0.0027862199800823455,
    0.0013839205421543163,0.0007605048676835544,-0.0029680689560234166,0.004428439196425601,
    -0.0044831515764064,0.0028949553116601945,2.1925915525784365e-17,-0.003331265325887765,
    0.0059375336605575245,-0.006753129043884384,0.005214659373206416,-0.0015406660788698883,
    -0.0032361036004170314,0.007529697079732869,-0.009700256440258416,0.008642845422652068,
    -0.004265115343618458,-0.0023331812123386884,0.009083601284026247,-0.013550543263792247,
    0.013749399593009245,-0.00892308461569403,-3.4062890961353726e-17,0.010469115721757096,
    -0.018945967401970524,0.021975293601780032,-0.017393845761407574,0.005299574612724601,
    0.01156290203473882,-0.028196011063579288,0.03849299299472846,-0.03686740341161849,
    0.019931630758706305,0.012263674390026897,-0.05582423681290944,0.10361856147838926,
    -0.14679216764687195,0.17682175931040572,0.8128236247590296,0.17682175931040572,
    -0.14679216764687195,0.10361856147838926,-0.05582423681290944,0.012263674390026897,
    0.01993163075870631,-0.03686740341161849,0.03849299299472846,-0.028196011063579288,
    0.01156290203473882,0.005299574612724601,-0.01739384576140758,0.021975293601780032,
    -0.01894596740197053,0.010469115721757096,-3.4062890961353726e-17,-0.008923084615694032,
    0.013749399593009245,-0.013550543263792248,0.009083601284026247,-0.002333181212338689,
    -0.004265115343618459,0.008642845422652068,-0.009700256440258414,0.0075296970797328715,
    -0.003236103600417032,-0.0015406660788698883,0.005214659373206418,-0.006753129043884385,
    0.0059375336605575245,-0.0033312653258877668,2.1925915525784368e-17,0.0028949553116601945,
    -0.0044831515764063995,0.0044284391964256025,-0.002968068956023417,0.0007605048676835542,
    0.0013839205421543167,-0.002786219980082346,0.0031011650776205674,-0.002383161510843877,
    0.0010123384560741628,0.0004756319450753634,-0.001586416050166716,0.0020217747765477402,
    -0.0017471076611631088,0.0009622870909900475,1.3192743492214583e-17,-0.0008035635123015404,
    0.001218460587898806,-0.0011779605890982878,0.0007725693980961322,-0.00019375049084193195,
    -0.00034532399164459324,0.0006817997752530305,-0.0007456859602351443,0.0005647008660650613,
    -0.00023731427604140918,-0.00011087499350943243,0.0003701519931112516,-0.00047598634622091665,
    0.00041905437859361927,-0.00023780079514758846,3.203029953990867e-18,0.00021915832706412156,
    -0.00035660257342508164};

const size_t kernelsz = sizeof(b) / sizeof(b[0]);

// Quick and dirty convolution
// result == signal_len + kernel_len - 1 */
void convolve(std::vector<float> signal,
              const float* kernel,
              size_t kernel_len,
              std::vector<float> &result)
{
    size_t kmin;
    size_t kmax;
    size_t signal_len = signal.size();

    result.resize(signal_len+kernel_len-1);

    for (int n = 0; n < signal_len + kernel_len - 1; n++)
    {
        result[n] = 0;

        kmin = (n >= kernel_len - 1) ? n - (kernel_len - 1) : 0;
        kmax = (n < signal_len - 1) ? n : signal_len - 1;

        for (size_t k = kmin; k <= kmax; k++)
            result[n] += signal[k] * kernel[n - k];
    }
}


std::vector<float> GenerateRandom(std::string name) {
    std::string str = name;
    std::size_t str_hash = std::hash<std::string>{}(str);
    LOGE("HASH: %s %d", str.c_str(), str_hash);

    // sample size
    double fs = 48000.0;

    // Transmit waveform duration (seconds)
    double d = 0.1;
    // Buffer size
    double buffSize = fs*d;

    std::mt19937 generator (str_hash);
    std::normal_distribution<float> dis(0, 1);

    std::vector<float> wave;
    wave.resize(buffSize);

    float current;
    for (int i = 0; i < buffSize; i++){
        current = dis(generator);
        wave[i] = current;
    }

    // ensure [-1,1]:
    float max = *std::max_element(wave.begin(), wave.end());

    for (int i = 0; i < buffSize; i++){
        wave[i] = wave[i]/max;
    }

    // apply filter
    std::vector<float> result;
    std::vector<float> result2;
    convolve(wave, b, kernelsz, result);
    convolve(result, lowpass, kernelsz, result2);
    wave=result2;

    // Again, ensure [-1,1]:
    max = *std::max_element(wave.begin(), wave.end());

    for (int i = 0; i < buffSize; i++){
        wave[i] = wave[i]/max;
    }
    // ramp
    double dRamp = 2.5e-2;
    double nRamp = int(fs*dRamp);
    //double nRamp = 200;

    for (int i = 0; i < nRamp-1; i++) {
        wave[i] *= float(i)/float(nRamp);
        wave[wave.size()-i] *= float(i)/float(nRamp);
    }

    return wave;
}
