/*
 * Company: Blackaddr Audio
 * Effect Name: Tuner
 * Description: A noise gate wtih controllable threshold, opening and closing times and DC removal filter. Basic tuner included. 
 *
 * This file was auto-generated by Aviate Audio Effect Creator for the Multiverse.
 */
#pragma once

#include <Audio.h>
#include <arm_math.h>
#include "Aviate/AudioEffectWrapper.h"

//!s - START_USER_INCLUDES - put your #includes below this line before the matching END
//!e - END_USER_INCLUDES

namespace BlackaddrAudio_Tuner {

//!s - START_USER_EFFECT_TYPES - put your effect types below this line before the matching END
//!e - END_USER_EFFECT_TYPES

class Tuner : public AudioStream, public Aviate::AudioEffectWrapper {
public:
    static constexpr unsigned NUM_INPUTS  = 1;
    static constexpr unsigned NUM_OUTPUTS = 1;

    // List of effect control names
    enum {
        Bypass_e = 0,
        Volume_e = 1,
        TunerSilent_e = 2,
        TunerCents_e = 3,
        TunerNote_e = 4,
        NUM_CONTROLS
    };

    //!s - START_USER_CLASS_TYPES - put your custom class types below this line before the matching END
    //!e - END_USER_CLASS_TYPES

    Tuner();

    //!s - START_USER_CONSTRUCTORS - put your custom constructors below this line before the matching END
    //!e - END_USER_CONSTRUCTORS

    virtual ~Tuner();

    // Standard EFX interface functions - do not change these declaration
    virtual void update(); // main audio processing loop function
    void mapMidiControl(int parameter, int midiCC, int midiChannel = 0) override;
    void processMidi(int channel, int midiCC, int value) override;
    void setParam(int paramIndex, float paramValue) override;
    float getUserParamValue(int paramIndex, float normalizedParamValue);
    const char* getName() override;
    const uint8_t* getRblk() override;

    // control value set functions, must take floats between 0.0f and 1.0f - do not change these declarations
    void volume(float value) override;
    void tunersilent(float value);
    void tunercents(float value);
    void tunernote(float value);

    //!s - START_USER_PUBLIC_MEMBERS - put your public members below this line before the matching END
    void bypass(bool byp) override;
    //!e - END_USER_PUBLIC_MEMBERS

private:
    audio_block_t *m_inputQueueArray[1]; // required by AudioStream base class, array size is num inputs
    int m_midiConfig[NUM_CONTROLS][2]; // stores the midi parameter mapping

    // m_bypass and m_volume are already provided by the base class AudioEffectWrapper
    float m_tunersilent = 0.0f;
    float m_tunercents = 0.0f;
    float m_tunernote = 0.0f;

    audio_block_t* m_basicInputCheck(audio_block_t* inputAudioBlock, unsigned outputChannel);

    //!s - START_USER_PRIVATE_MEMBERS - put your private members below this line before the matching END

    // Tuner
    // code excerpts from Teensy Audio Library analyze_notefreq.*
    static constexpr unsigned AUDIO_GUITARTUNER_BLOCKS = 24;
    uint64_t running_sum;
    uint16_t tau_global;
    uint64_t yin_buffer[5];
    uint64_t rs_buffer[5];
    int16_t  AudioBuffer[AUDIO_GUITARTUNER_BLOCKS*128] __attribute__ ( ( aligned ( 4 ) ) );
    uint8_t  yin_idx, state;
    float    periodicity, yin_threshold, cpu_usage_max, data;
    bool     next_buffer, first_run;
    volatile bool new_output = false, process_buffer;
    audio_block_t *blocklist1[AUDIO_GUITARTUNER_BLOCKS];
    audio_block_t *blocklist2[AUDIO_GUITARTUNER_BLOCKS];

    bool m_initialized = false;
    bool m_tunerEnabled = false;
    bool m_silentEnabled = false;
    unsigned m_skipUpdateCount = 0;
    bool m_signalDetect = false;
    float m_dcValueSum = 0.0f;
    float m_dcValue = 0.0f;
    unsigned m_dcValueCount = 0;
    bool m_calibrateEnabled = false;
    bool m_startupInProgress = true;


    static constexpr float m_ALPHA = 0.95f;
    static constexpr float m_ONE_MINUS_ALPHA = 1.0f - m_ALPHA;
    float m_centsFiltered = 0.0f;
    //SysPlatform::ElapsedMillis m_timer;

    bool available( void );
    float probability( void );
    float read( void );
    uint16_t estimate( uint64_t *yin, uint64_t *rs, uint16_t head, uint16_t tau );
    void process( void );
    void tunerReset();
    void init( float thresholdIn );
    static void copy_buffer(void *destination, const void *source);

    //!e - END_USER_PRIVATE_MEMBERS

};

}
