MFCC
======

计算梅尔频率倒谱系数（Mel-Frequency Cepstral Coefficients）。

.. math::

    MFCC_i = f(Input_i)

输入：
    - **mfcc\_params** - MFCC 计算相关的配置参数，如采样率、梅尔滤波器数量等。
    - **spec\_params** - 频谱计算参数，定义了FFT窗口大小、重叠长度等。
    - **mfcc\_workspace** - 工作空间参数，包括计算所需的中间缓冲区。
    - **spec\_workspace** - 频谱计算的工作空间，包括FFT的窗口、输入数据等。
    - **core\_mask** (可选) - 核掩码（仅适用于多核版本）。

输出：
    - **output(mfcc\_params中)** - 计算结果地址，存储MFCC特征。
    - **output_shape(mfcc\_params中)** - 输出数据的形状，描述MFCC特征的维度。

**结构体定义：**
    .. code-block:: c
        :linenos:

            typedef struct {
                // 输入/输出
                float* input;           // 输入数据地址
                int* input_shape;       // 输入数据形状
                float* output;          // 输出数据地址
                int* output_shape;      // 输出数据形状
                
                // 配置参数
                int sample_rate;        // 采样率
                int n_mfcc;            // MFCC系数数量
                int dct_type;           // DCT变换类型
                bool log_mels;          // 是否对梅尔频谱取对数
                float f_min;            // 最小频率
                float f_max;            // 最大频率
                int n_mels;             // 梅尔滤波器数量
                NormType norm;          // 归一化类型
                NormMode norm_M;        // 归一化模式
                MelType mel_scale;      // 梅尔尺度类型
            } MfccParam;

            typedef struct {
                // 输入
                float* input;           // 输入数据地址
                int input_len;          // 输入数据长度
                
                // 输出
                float* output;          // 输出数据地址
                int* output_shape;      // 输出数据形状
                
                // 配置参数
                int pad;                // 填充大小
                WindowType window_type; // 窗函数类型
                int n_fft;              // FFT点数
                int hop_length;         // 帧移长度
                int win_length;         // 窗长度
                float power;            // 功率值
                bool normalized;        // 是否归一化
                bool center;            // 是否中心化
                BorderType pad_mode;    // 填充模式
                bool onesided;          // 是否单边频谱
            } SpectrogramParam;

            typedef struct {
                // 滤波器组计算缓冲区
                float *all_freqs;       // 所有频率点
                float *m_pts;           // 梅尔频率点
                float *f_pts;           // 线性频率点
                float *fb;              // 滤波器组
                
                // 三角滤波器计算缓冲区
                float *f_diff;          // 频率差值
                float *slopes;          // 斜率
                float *down_slopes;     // 下降斜率
                float *up_slopes;       // 上升斜率
                
                // DCT变换缓冲区
                float* dct_mat;         // DCT矩阵
                
                // 中间结果缓冲区
                float* spectrogram_output;          // 频谱图输出
                float* mel_spectrogram_output;      // 梅尔频谱输出
            } MfccWorkspaceParam;

            typedef struct {
                float* fft_window;          // FFT窗函数缓冲区
                float* fft_window_later;    // 后续FFT窗缓冲区
                float* input_data_pad;      // 填充后的输入数据
                float* input_data;          // 输入数据缓冲区
                float* input_win;           // 加窗输入数据
                float* exp_complex;         // 复数指数缓冲区
                float* spec_f;              // 频谱频率缓冲区
                float* output_onsided;      // 单边输出缓冲区
            } WorkspaceParam;
支持平台：
    ``FT78NE``  
    ``MT7004``

.. note::
    - FT78NE 支持 fp32
    - MT7004 支持 fp32, fp16

**共享存储版本:**

.. c:function:: void fp_mfcc_s(const MfccParam* mfcc_params, SpectrogramParam* spec_params, MfccWorkspaceParam* mfcc_workspace, WorkspaceParam* spec_workspace, int core_mask)
.. c:function:: void hp_mfcc_s(const MfccParam* mfcc_params, SpectrogramParam* spec_params, MfccWorkspaceParam* mfcc_workspace, WorkspaceParam* spec_workspace, int core_mask)

    **C调用示例：**

    .. code-block:: c
        :linenos:
        :emphasize-lines: 45

        //FT78NE示例
        #include <stdio.h>
        
        int main(int argc, char* argv[]) {
            float* input_data = (float*)0x81000000;
            float* output_mfcc = (float*)0x82000000;
            int input_shape[2] = {1, 4000};
            int output_shape[2] = {0, 0, 0};
            MfccParam* mfcc_params = (MfccParam*)0x83100000;
            SpectrogramParam* spec_params = (SpectrogramParam*)0x83200000;
            MfccWorkspaceParam* mfcc_workspace = (MfccWorkspaceParam*)0x83300000;
            WorkspaceParam* spec_workspace = (WorkspaceParam*)0x83400000;

            mfcc_params->input = input_data;
            mfcc_params->input_shape = input_shape;
            mfcc_params->output = output_mfcc;
            mfcc_params->output_shape = output_shape;
            mfcc_params->sample_rate = 800;
            mfcc_params->n_mfcc = 6;
            mfcc_params->dct_type = 2;
            mfcc_params->log_mels = true;
            mfcc_params->f_min = 0.0f;
            mfcc_params->f_max = 400.0f;
            mfcc_params->n_mels = 8;
            mfcc_params->norm = NORM_SLANEY;
            mfcc_params->norm_M = NORM_MODE_ORTHO;
            mfcc_params->mel_scale = MEL_HTK;

            // 结构体 2: SpectrogramParam
            spec_params->pad = 0;
            spec_params->window_type = kHann;
            spec_params->n_fft = 32;
            spec_params->hop_length = 16;
            spec_params->win_length = 32;
            spec_params->power = 2.0f;
            spec_params->normalized = false;
            spec_params->center = false;
            spec_params->pad_mode = kConstant;
            spec_params->onesided = true;

            int core_mask = 0xff;
            //为mfcc_workspace和spec_workspace里每个中间缓冲区指针分配地址
            //...

            fp_mfcc_s(mfcc_params, spec_params, mfcc_workspace, spec_workspace, core_mask);
            return 0;
        }

**私有存储版本:**

.. c:function:: void fp_mfcc_p(const MfccParam* mfcc_params, SpectrogramParam* spec_params, MfccWorkspaceParam* mfcc_workspace, WorkspaceParam* spec_workspace)
.. c:function:: void hp_mfcc_p(const MfccParam* mfcc_params, SpectrogramParam* spec_params, MfccWorkspaceParam* mfcc_workspace, WorkspaceParam* spec_workspace)

    **C调用示例：**

    .. code-block:: c
        :linenos:
        :emphasize-lines: 45

        //FT78NE示例
        #include <stdio.h>
        
        int main(int argc, char* argv[]) {
            MfccParam mfcc_params;
            SpectrogramParam spec_params;
            MfccWorkspaceParam mfcc_workspace;
            WorkspaceParam spec_workspace;

            float* input_data = (float*)0x10810000;
            float* output_mfcc = (float*)0x10820000;
            int input_shape[2] = {1, 4000};
            int output_shape[2] = {0, 0, 0};

            mfcc_params.input = input_data;
            mfcc_params.input_shape = input_shape;
            mfcc_params.output = output_mfcc;
            mfcc_params.output_shape = output_shape;
            mfcc_params.sample_rate = 800;
            mfcc_params.n_mfcc = 6;
            mfcc_params.dct_type = 2;
            mfcc_params.log_mels = true;
            mfcc_params.f_min = 0.0f;
            mfcc_params.f_max = 400.0f;
            mfcc_params.n_mels = 8;
            mfcc_params.norm = NORM_SLANEY;
            mfcc_params.norm_M = NORM_MODE_ORTHO;
            mfcc_params.mel_scale = MEL_HTK;

            // 结构体 2: SpectrogramParam
            spec_params.pad = 0;
            spec_params.window_type = kHann;
            spec_params.n_fft = 32;
            spec_params.hop_length = 16;
            spec_params.win_length = 32;
            spec_params.power = 2.0f;
            spec_params.normalized = false;
            spec_params.center = false;
            spec_params.pad_mode = kConstant;
            spec_params.onesided = true;

            //为mfcc_workspace和spec_workspace里每个中间缓冲区指针分配地址
            //...

            fp_mfcc_p(&mfcc_params, &spec_params, &mfcc_workspace, &spec_workspace);
            return 0;
        }
