/*
 ****************************************************************
 *File : audio_dec_midi_file.c
 *Note :
 *
 ****************************************************************
 */
//////////////////////////////////////////////////////////////////////////////
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "effectrs_sync.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "app_config.h"
#include "app_main.h"
#include "MIDI_DEC_API.h"
#include "audio_dec_file.h"
#include "lfwordana_enc_api.h"

#if defined(TCFG_DEC_MIDI_ENABLE) && TCFG_DEC_MIDI_ENABLE
//midi文件播放时，对应的音色文件路径(用户可修改路径)
#define MIDI_FILE_PATH  SDFILE_RES_ROOT_PATH"MIDI.bin\0"
//替换主旋律的音色库，由录音得到(用户可修改路径)
int *MIDI_W2S_FILE_PATH = "storage/sd0/C/W2S/W2S.raw\0";
//替换主旋律音色库对应的参数文件,录音时生成(用户可修改路径)
#define MIDI_W2S_PARM_PATH "storage/sd0/C/W2S/parmout.raw\0"

static const u16 midi_samplerate_tab[9] = {
    48000,
    44100,
    32000,
    24000,
    22050,
    16000,
    12000,
    11025,
    8000
};
static u32 get_sr_tab_num(u32 sr)
{
    int i = 0;
    for (i = 0; i < ARRAY_SIZE(midi_samplerate_tab); i++) {
        if (sr == midi_samplerate_tab[i]) {
            return i;
        }
    }
    return 4;
}
u32 tmark_trigger(void *priv, u8 *val, u8 len)
{
    return 0;
}

u32 melody_trigger(void *priv, u8 key, u8 vel)
{
    return 0;
}

u32 melody_stop_trigger(void *priv, u8 key)
{
    return 0;
}

u32 timDiv_trigger(void *priv)
{
    return 0;
}

u32 beat_trigger(void *priv, u8 val1/*一节多少拍*/, u8 val2/*每拍多少分音符*/)
{
    return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief    midi音色文件读
   @param
   @return
   @note     内部调用
*/
/*----------------------------------------------------------------------------*/
int midi_fread(void *file, void *buf, u32 len)
{

#ifndef CONFIG_MIDI_DEC_ADDR
    FILE *hd = (FILE *)file;
    if (hd) {
        len = fread(hd, buf, len);
    }
#endif
    return len;
}
/*----------------------------------------------------------------------------*/
/**@brief    midi音色文件seek
   @param
   @return
   @note     内部调用
*/
/*----------------------------------------------------------------------------*/
int midi_fseek(void *file, u32 offset, int seek_mode)
{
#ifndef CONFIG_MIDI_DEC_ADDR
    FILE *hd = (FILE *)file;
    if (hd) {
        fseek(hd, offset, seek_mode);
    }
#endif
    return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief    midi初始化函数，由midi_init调用
   @param    midi_init_info_v:midi信息
   @param    addr:音色文件句柄
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
void init_midi_info_val(MIDI_INIT_STRUCT  *midi_init_info_v, void *addr)
{
    //midi初始化表
    midi_init_info_v->init_info.player_t = 8;
    midi_init_info_v->init_info.sample_rate = get_sr_tab_num(22050);
    midi_init_info_v->init_info.spi_pos = (u32)addr;
    midi_init_info_v->init_info.fread = midi_fread;
    midi_init_info_v->init_info.fseek = midi_fseek;


    //midi的模式初始化
    midi_init_info_v->mode_info.mode = CMD_MIDI_CTRL_MODE_0; //CMD_MIDI_CTRL_MODE_2;

    //midi节奏初始化
    midi_init_info_v->tempo_info.tempo_val = 1042;

    for (u32 tmp_i = 0; tmp_i < 16; tmp_i++) {
        midi_init_info_v->tempo_info.decay_val[tmp_i] = ((u16)31 << 11) | 1024;
    }
    midi_init_info_v->tempo_info.mute_threshold = (u16)1L << 29;

    //midi主轨道初始化
    midi_init_info_v->mainTrack_info.chn = 17; //把哪个轨道当成主轨道 , 17:库内自动分配

    //midi外部音量初始化
    for (u32 tmp_i = 0; tmp_i < 16; tmp_i++) {
        midi_init_info_v->vol_info.cc_vol[tmp_i] = 4096; //4096即原来的音量
    }
    midi_init_info_v->vol_info.ex_vol_use_chn = 1;

    //midi的主轨道乐器设置
    midi_init_info_v->prog_info.prog = 0;
    midi_init_info_v->prog_info.ex_vol = 1024;
    midi_init_info_v->prog_info.replace_mode = 0;

    //OKON 模式设置
    midi_init_info_v->okon_info.Melody_Key_Mode = CMD_MIDI_MELODY_KEY_0;
    midi_init_info_v->okon_info.OKON_Mode = CMD_MIDI_OKON_MODE_0;


    //midi的mark控制初始化
    midi_init_info_v->mark_info.priv = NULL; //&file_mark;
    midi_init_info_v->mark_info.mark_trigger = tmark_trigger;

    //midi的melody控制初始化
    midi_init_info_v->moledy_info.priv = NULL; //&file_melody;
    midi_init_info_v->moledy_info.melody_trigger = melody_trigger;

    //midi的melody stop控制初始化
    midi_init_info_v->moledy_stop_info.priv = NULL;
    midi_init_info_v->moledy_stop_info.melody_stop_trigger = melody_stop_trigger;//主旋律音符停止播放回调

    //midi的小节回调控制初始化
    midi_init_info_v->tmDiv_info.priv = NULL;
    midi_init_info_v->tmDiv_info.timeDiv_trigger = timDiv_trigger;

    //midi的小拍回调控制初始化
    midi_init_info_v->beat_info.priv = NULL;
    midi_init_info_v->beat_info.beat_trigger = beat_trigger;

    //使能位控制
    midi_init_info_v->switch_info = MELODY_PLAY_ENABLE;// | MELODY_ENABLE | EX_VOL_ENABLE;            //主轨道播放使能

#if defined(MIDI_SUPPORT_W2S) && MIDI_SUPPORT_W2S
    //设置替换主轨道的声音的音源
    void *cache_addr;
    extern int midi_w2s_get_cfg_addr(void **addr);
    if (midi_w2s_get_cfg_addr(&cache_addr)) {
        log_e("get midi w2s addr err\n");
        return;
    }
    midi_w2s_parm_get(&midi_init_info_v->w2s_info);
    midi_init_info_v->w2s_info.key_diff = -7;////与音高成反比
    midi_init_info_v->w2s_info.rec_data = (u32)cache_addr;
#endif/*MIDI_SUPPORT_W2S*/
    return;
}

FILE  *midi_w2s_file = NULL;
int midi_w2s_get_cfg_addr(void **addr)
{
#ifndef CONFIG_MIDI_DEC_ADDR
    //音色文件支持在外部存储卡或者外挂flash,sdk默认使用本方式
    //获取音色文件
    FILE  *file = fopen(MIDI_W2S_FILE_PATH, "r");
    if (!file) {
        log_e("MIDI.bin open err\n");
        return -1;
    }
    *addr = (void *)file;
    midi_w2s_file = file;
    log_i("midi_w2s_file %x\n", midi_w2s_file);
#else
    //音色文件仅支持在内置flash
    FILE  *file = fopen(MIDI_W2S_FILE_PATH, "r");
    if (!file) {
        log_e("MIDI.bin open err\n");
        return -1;
    }

    struct vfs_attr attr = {0};
    fget_attrs(file, &attr);
    *addr = (void *)attr.sclust;
    fclose(file);
#endif

    return 0;
}


FILE  *midi_file = NULL;
int midi_get_cfg_addr(void **addr)
{
#ifndef CONFIG_MIDI_DEC_ADDR
    //音色文件支持在外部存储卡或者外挂flash,sdk默认使用本方式
    //获取音色文件
    FILE  *file = fopen(MIDI_FILE_PATH, "r");
    if (!file) {
        log_e("MIDI.bin open err\n");
        return -1;
    }
    *addr = (void *)file;
    midi_file = file;
    log_i("midi_file %x\n", midi_file);
#else
    //音色文件仅支持在内置flash
    FILE  *file = fopen(MIDI_FILE_PATH, "r");
    if (!file) {
        log_e("MIDI.bin open err\n");
        return -1;
    }

    struct vfs_attr attr = {0};
    fget_attrs(file, &attr);
    *addr = (void *)attr.sclust;
    fclose(file);
#endif

    return 0;
}

/*----------------------------------------------------------------------------*/
/**@brief    midi音色文件关闭
   @param
   @return
   @note     该函数在midi关闭时调用,该函数是弱定义函数，不可修改定义
*/
/*----------------------------------------------------------------------------*/
int midi_uninit()
{
#ifndef CONFIG_MIDI_DEC_ADDR
    if (midi_file) {
        fclose(midi_file);
        midi_file = NULL;
    }

    if (midi_w2s_file) {
        fclose(midi_w2s_file);
        midi_w2s_file = NULL;
    }
#endif
    return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief    midi初始化函数，该函数由库调用
   @param    参数返回地址
   @return   0
   @note     该函数是弱定义函数，不可修改定义
*/
/*----------------------------------------------------------------------------*/
int midi_init(void *info)
{
    void *cache_addr;
    if (midi_get_cfg_addr(&cache_addr)) {
        log_e("get midi addr err\n");
        return -1;
    }
    //初始化midi参数
    init_midi_info_val(info, cache_addr);  //需要外部写
    return 0;
}

/*----------------------------------------------------------------------------*/
/**@brief    midi控制函数
	@param   cmd:
		     CMD_MIDI_SET_CHN_PROG,  //更改乐器,参数结构对应 MIDI_PROG_CTRL_STRUCT
		     CMD_MIDI_CTRL_TEMPO,    //改变节奏,参数结构对应 MIDI_PLAY_CTRL_TEMPO
		     CMD_MIDI_GOON,          //one key one note的时候接着播放使用,参数为空
		     CMD_MIDI_CTRL_MODE,     //改变模式,参数结构对应 MIDI_PLAY_CTRL_MO
		     CMD_MIDI_SET_SWITCH,    //配置开关使能，要不要替换乐器，使用外部音量,参数对应 MIDI_SET_SWITCH
		     CMD_MIDI_SET_EX_VOL,    //设置外部声道音量,参数结构对应 EX_CH_VOL_PARM
   @param    priv:对应cmd的参数地址
   @return   0
   @note    midi解码控制例程
*/
/*----------------------------------------------------------------------------*/
void midi_ioctrl(u32 cmd, void *priv)
{
    struct file_dec_hdl *dec = get_file_dec_hdl();	// 文件解码句柄
    if (dec) {
        log_e("file dec NULL\n");
        return ;
    }

    int status = file_dec_get_status();
    if (status == FILE_DEC_STATUS_STOP) {
        if (tone_get_dec_status()) {
            audio_decoder_ioctrl(get_tone_dec_file_decoder(), cmd, priv);
        } else {
            log_w("file dec is stop\n");
        }
        return ;
    }

    log_i("midi cmd %x", cmd);
    audio_decoder_ioctrl(&dec->file_dec.decoder, cmd, priv);
}
#if 0
//测试例子
void *ex_vol_test()
{
    static int val = 4096;
    EX_CH_VOL_PARM ex_vol;
    for (int test_ci = 0; test_ci < CTRL_CHANNEL_NUM; test_ci++) {
        ex_vol.cc_vol[test_ci] = val;
    }
    val -= 64;
    if (val <= 0) {
        val = 4096;
    }
    midi_ioctrl(CMD_MIDI_SET_EX_VOL, &ex_vol);
    return NULL;
}
#endif


#if defined(MIDI_SUPPORT_W2S) && MIDI_SUPPORT_W2S
int midi_w2s_init(void *info)
{
    struct _AUDIO_DECODE_PARA {
        u32 mode;
    };
    struct _AUDIO_DECODE_PARA *mode_parm = (struct _AUDIO_DECODE_PARA *)info;
    mode_parm->mode = CMD_MIDI_CTRL_MODE_W2S;
    return 0;
}


/*----------------------------------------------------------------------------*/
/**@brief    midi主旋律是否用录音文件替换主旋律
   @param    flag:1(替换主旋律)  0(不替换主旋律)
   @return   无
   @note
*/
/*----------------------------------------------------------------------------*/
void midi_mode_change(u8 flag)
{
    struct _AUDIO_DECODE_PARA {
        u32 mode;
    };
    struct _AUDIO_DECODE_PARA mode_parm = {0};
    if (flag) {
        mode_parm.mode = CMD_MIDI_CTRL_MODE_W2S;
    } else {
        mode_parm.mode = CMD_MIDI_CTRL_MODE_0;
    }
    midi_ioctrl(CMD_MIDI_CTRL_MODE, &mode_parm);
}

void midi_mode_test(void *p)
{
    static u8 flag = 0;
    midi_mode_change(flag);
    flag = !flag;
}
#endif/*MIDI_SUPPORT_W2S*/

/*----------------------------------------------------------------------------*/
/**@brief    midi预处理的音色，对应的输出的参数
   @param    data:参数地址
   @param    len:参数长度
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
void midi_w2s_parm_set(void *data, u32 len)
{
    MIDI_W2S_STRUCT *w2s_parmOut;
    void *fp = fopen(MIDI_W2S_PARM_PATH, "wb");
    if (fp) {
        fwrite(fp, data, len);
        fclose(fp);
        fp = NULL;
    }
}
/*----------------------------------------------------------------------------*/
/**@brief    获取midi预处理的音色，对应的参数
   @param    parm:参数返回地址
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
void midi_w2s_parm_get(void *parm)
{
    void *fp = fopen(MIDI_W2S_PARM_PATH, "r");
    if (fp) {
        fread(fp, parm, sizeof(MIDI_W2S_STRUCT));
        fclose(fp);
        fp = NULL;
    }
}


#endif /*TCFG_DEC_MIDI_ENABLE*/
