# -*- coding: utf-8 -*-
"""
@author:XuMing(xuming624@qq.com)
@description:
"""
import math
import wave
import numpy as np
import difflib


def edit_distance(str1, str2):
    distance = 0
    s = difflib.SequenceMatcher(None, str1, str2)
    for tag, i1, i2, j1, j2 in s.get_opcodes():
        # print('{:7} a[{}: {}] --> b[{}: {}] {} --> {}'.format(tag, i1, i2, j1, j2, str1[i1: i2], str2[j1: j2]))
        if tag == 'replace':
            distance += max(i2 - i1, j2 - j1)
        elif tag == 'insert':
            distance += (j2 - j1)
        elif tag == 'delete':
            distance += (i2 - i1)
    return distance


def read_wav_data(filename):
    """
    读取一个wav文件，返回声音信号的时域谱矩阵和播放时间
    """
    wav = wave.open(filename, "rb")  # 打开一个wav格式的声音文件流
    num_frame = wav.getnframes()  # 获取帧数
    num_channel = wav.getnchannels()  # 获取声道数
    framerate = wav.getframerate()  # 获取帧速率
    str_data = wav.readframes(num_frame)  # 读取全部的帧
    wav.close()  # 关闭流
    wave_data = np.fromstring(str_data, dtype=np.short)  # 将声音文件数据转换为数组矩阵形式
    wave_data.shape = -1, num_channel  # 按照声道数将数组整形，单声道时候是一列数组，双声道时候是两列的矩阵
    wave_data = wave_data.T  # 将矩阵转置
    return wave_data, framerate


def GetFrequencyFeature(wavsignal, fs):
    from scipy.fftpack import fft
    # wav波形 加时间窗以及时移10ms
    time_window = 25  # 单位ms
    data_input = []

    # print(int(len(wavsignal[0])/fs*1000 - time_window) // 10)
    wav_length = len(wavsignal[0])  # 计算一条语音信号的原始长度
    range0_end = int(len(wavsignal[0]) / fs * 1000 - time_window) // 10  # 计算循环终止的位置，也就是最终生成的窗数
    for i in range(0, range0_end):
        p_start = i * 160
        p_end = p_start + 400
        data_line = []

        for j in range(p_start, p_end):
            data_line.append(wavsignal[0][j])
        # print('wavsignal[0][j]:\n',wavsignal[0][j])
        # data_line = abs(fft(data_line)) / len(wavsignal[0])
        data_line = fft(data_line) / wav_length
        data_line2 = []
        for fre_sig in data_line:
            # 分别取出频率信号的实部和虚部作为语音信号的频率特征
            # 直接使用复数的话，之后会被numpy将虚部丢弃，造成信息丢失
            # print('fre_sig:\n',fre_sig)
            data_line2.append(fre_sig.real)
            data_line2.append(fre_sig.imag)

        data_input.append(data_line2[0:len(data_line2) // 2])  # 除以2是取一半数据，因为是对称的
    return data_input


def GetFrequencyFeature2(wavsignal, fs):
    from scipy.fftpack import fft
    # wav波形 加时间窗以及时移10ms
    time_window = 25  # 单位ms
    window_length = fs / 1000 * time_window  # 计算窗长度的公式，目前全部为400固定值

    wav_arr = np.array(wavsignal)
    # wav_length = len(wavsignal[0])
    wav_length = wav_arr.shape[1]

    range0_end = int(len(wavsignal[0]) / fs * 1000 - time_window) // 10  # 计算循环终止的位置，也就是最终生成的窗数
    data_input = np.zeros((range0_end, 200), dtype=np.float)  # 用于存放最终的频率特征数据
    data_line = np.zeros((1, 400), dtype=np.float)
    for i in range(0, range0_end):
        p_start = i * 160
        p_end = p_start + 400

        data_line = wav_arr[0, p_start:p_end]
        """
        x=np.linspace(0, 400 - 1, 400, dtype = np.int64)
        w = 0.54 - 0.46 * np.cos(2 * np.pi * (x) / (400 - 1) ) # 汉明窗
        data_line = data_line * w # 加窗
        """
        data_line = np.abs(fft(data_line)) / wav_length

        data_input[i] = data_line[0:200]  # 设置为400除以2的值(即200）是取一半数据，因为是对称的

    # print(data_input.shape)
    return data_input


x = np.linspace(0, 400 - 1, 400, dtype=np.int64)
w = 0.54 - 0.46 * np.cos(2 * np.pi * (x) / (400 - 1))  # 汉明窗


def get_frequency_features(wavsignal, fs):
    from scipy.fftpack import fft
    # wav波形 加时间窗以及时移10ms
    time_window = 25  # 单位ms
    window_length = fs / 1000 * time_window  # 计算窗长度的公式，目前全部为400固定值

    wav_arr = np.array(wavsignal)
    wav_length = wav_arr.shape[1]

    range0_end = int(len(wavsignal[0]) / fs * 1000 - time_window) // 10  # 计算循环终止的位置，也就是最终生成的窗数
    data_input = np.zeros((range0_end, 200), dtype=np.float)  # 用于存放最终的频率特征数据
    data_line = np.zeros((1, 400), dtype=np.float)

    for i in range(0, range0_end):
        p_start = i * 160
        p_end = p_start + 400
        data_line = wav_arr[0, p_start:p_end]
        data_line = data_line * w  # 加窗
        data_line = np.abs(fft(data_line)) / wav_length
        data_input[i] = data_line[0:200]  # 设置为400除以2的值(即200）是取一半数据，因为是对称的

    # print(data_input.shape)
    data_input = np.log(data_input + 1)
    return data_input


def wav_scale(energy):
    """
    语音信号能量归一化
    """
    means = energy.mean()  # 均值
    var = energy.var()  # 方差
    e = (energy - means) / math.sqrt(var)  # 归一化能量
    return e


def wav_scale2(energy):
    """
    语音信号能量归一化
    """
    maxnum = max(energy)
    e = energy / maxnum
    return e


def wav_scale3(energy):
    """
    语音信号能量归一化
    """
    for i in range(len(energy)):
        # if i == 1:
        #	#print('wavsignal[0]:\n {:.4f}'.format(energy[1]),energy[1] is int)
        energy[i] = float(energy[i]) / 100.0
    # if i == 1:
    #	#print('wavsignal[0]:\n {:.4f}'.format(energy[1]),energy[1] is int)
    return energy


def get_wav_list(filename):
    """
    读取一个wav文件列表，返回一个存储该列表的字典类型值
    ps:在数据中专门有几个文件用于存放用于训练、验证和测试的wav文件列表
    """
    txt_obj = open(filename, 'r')  # 打开文件并读入
    txt_text = txt_obj.read()
    txt_lines = txt_text.split('\n')  # 文本分割
    dic_filelist = {}  # 初始化字典
    list_wavmark = []  # 初始化wav列表
    for i in txt_lines:
        if i != '':
            txt_l = i.split(' ')
            dic_filelist[txt_l[0]] = txt_l[1]
            list_wavmark.append(txt_l[0])
    txt_obj.close()
    return dic_filelist, list_wavmark


def get_wav_symbol(filename):
    """
    读取指定数据集中，所有wav文件对应的语音符号
    返回一个存储符号集的字典类型值
    """
    txt_obj = open(filename, 'r')  # 打开文件并读入
    txt_text = txt_obj.read()
    txt_lines = txt_text.split('\n')  # 文本分割
    dic_symbol_list = {}  # 初始化字典
    list_symbolmark = []  # 初始化symbol列表
    for i in txt_lines:
        if i != '':
            txt_l = i.split(' ')
            dic_symbol_list[txt_l[0]] = txt_l[1:]
            list_symbolmark.append(txt_l[0])
    txt_obj.close()
    return dic_symbol_list, list_symbolmark


def get_pinyin_list(dict_path=''):
    """
    加载拼音符号列表，用于标记符号
    :param dict_path: 拼音符号列表
    :return:
    """
    list_symbol = []  # 符号列表
    pinyin_idx = 0
    with open(dict_path, mode='r', encoding='UTF-8') as f:
        for line in f:
            line = line.strip('\n')
            parts = line.split('\t')
            list_symbol.append(parts[pinyin_idx])
    list_symbol.append('_')
    return list_symbol
