python 将语音转为吉他谱

吉他谱生成参考


https://blog.csdn.net/xufive/article/details/113246579

吉他谱生成音乐代码

import numpy as np
from scipy.io import wavfile
SPEED = 80  # 用每分钟节拍数表示弹奏速度
FRAME_RATE = 44100  # 采样速率(44100为CD音质,22050为调频广播音质)
STEREO = True  # 立体声(双声道)

# 生成吉他音色包络线
x = np.linspace(0, 3 * np.pi, 2 * int(FRAME_RATE * 60 / SPEED), endpoint=False)
y1 = 1 - x / (10 * np.pi) + (1 - x / (6 * np.pi)) * np.sin(x) * 0.5
x = np.arange(6 * int(FRAME_RATE * 60 / SPEED)) / int(FRAME_RATE * 60 / SPEED)
y2 = 0.7 * np.exp(-x)
GUITAR_EFFECT_ARRAY = np.hstack((y1, y2))


def get_frequency(pos):
    """返回指定弦品pos的频率"""

    fs = (329.6, 246.9, 196.0, 146.8, 110.0, 82.4)
    if pos[0] == '0':
        return 0
    else:
        return fs[int(pos[0]) - 1] * pow(2, int(pos[1:]) / 12)


def get_wave(f, beat):
    """返回指定频率和节拍数的波形数据"""

    data = list()
    duration = beat * 60 / SPEED
    sample_num = int(duration * FRAME_RATE)

    for k, p in [(1, 0.4), (2, 0.3), (3, 0.2), (4, 0.1)]:
        x = np.linspace(0, 2 * duration * f * k * np.pi, sample_num, endpoint=False)
        y = np.sin(x) * p
        data.append(y)

    return guitar_effect(np.sum(np.dstack(data)[0], axis=1))


def guitar_effect(data):
    """将等幅声波变成吉他音色的声波数据"""

    return data * GUITAR_EFFECT_ARRAY[:data.shape[0]]


def play(melody):
    """弹奏吉他谱,若wave_file存在,同时生成.wav文件"""

    data = list()
    for section in melody:
        data_section = list()
        for cord in section:
            data_cord = list()
            for pos, beat in cord:
                f = get_frequency(pos)
                dw = get_wave(f, beat)
                data_cord.append(dw)
            data_cord = np.hstack(data_cord)
            data_section.append(data_cord)

        d = data_section[0]
        for i in range(1, len(data_section)):
            if d.shape[0] > data_section[i].shape[0]:
                d[:data_section[i].shape[0]] += data_section[i]
            else:
                data_section[i][:d.shape[0]] += d
                d = data_section[i]
        data.append(d)

    data = np.hstack(data)
    data = data * 20000 / data.max()
    data = data.astype(np.int16)

    if STEREO:
        blank = np.zeros(int(0.006 * FRAME_RATE), dtype=np.int16)
        d_left = np.hstack((data, blank))
        d_right = np.hstack((blank, data))
        data = np.dstack((d_left, d_right))[0].ravel()
        wavfile.write("160_1_recorded2_001_normal_copy.wav",  44100, data)


romance= [
    [
        [('17',1),('17',1),('17',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('17',1),('15',1),('13',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('13',1),('12',1),('10',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('10',1),('13',1),('17',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('112',1),('112',1),('112',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('112',1),('110',1),('18',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('18',1),('17',1),('15',1)],
        [('0',0.33),('25',1),('25',1),('25',0.66)],
        [('0',0.66),('35',1),('35',1),('35',0.33)],
        [('50',3)]
    ],
    [
        [('15',1),('17',1),('18',1)],
        [('0',0.33),('25',1),('25',1),('25',0.66)],
        [('0',0.66),('35',1),('35',1),('35',0.33)],
        [('50',3)]
    ],
    [
        [('17',1),('18',1),('17',1)],
        [('0',0.33),('27',1),('27',1),('27',0.66)],
        [('0',0.66),('38',1),('38',1),('38',0.33)],
        [('67',3)]
    ],
    [
        [('111',1),('18',1),('17',1)],
        [('0',0.33),('27',1),('27',1),('27',0.66)],
        [('0',0.66),('38',1),('38',1),('38',0.33)],
        [('67',3)]
    ],
    [
        [('17',1),('15',1),('13',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('13',1),('12',1),('10',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('60',3)]
    ],
    [
        [('12',1),('12',1),('12',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('32',1),('32',1),('32',0.33)],
        [('52',3)]
    ],
    [
        [('12',1),('13',1),('12',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('32',1),('32',1),('32',0.33)],
        [('52',3)]
    ],
    [
        [('10',1),('10',1),('10',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('30',1),('30',1),('30',0.33)],
        [('42',1),('52',1),('63',1)]
    ],
    [
        [('10',3)],
        [('20',3)],
        [('30',3)],
        [('60',3)]
    ],
    [
        [('14',1),('14',1),('14',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('31',1),('31',1),('31',0.33)],
        [('60',3)]
    ],
    [
        [('14',1),('12',1),('10',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('31',1),('31',1),('31',0.33)],
        [('60',3)]
    ],
    [
        [('25',1),('24',1),('24',1)],
        [('0',0.33),('32',1),('32',1),('32',0.66)],
        [('0',0.66),('44',1),('44',1),('44',0.33)],
        [('50',3)]
    ],
    [
        [('24',1),('23',1),('24',1)],
        [('0',0.33),('32',1),('32',1),('32',0.66)],
        [('0',0.66),('44',1),('44',1),('44',0.33)],
        [('50',3)]
    ],
    [
        [('19',1),('19',1),('19',1)],
        [('0',0.33),('27',1),('27',1),('27',0.66)],
        [('0',0.66),('38',1),('38',1),('38',0.33)],
        [('67',3)]
    ],
    [
        [('19',1),('111',1),('19',1)],
        [('0',0.33),('27',1),('27',1),('27',0.66)],
        [('0',0.66),('38',1),('38',1),('38',0.33)],
        [('67',3)]
    ],
    [
        [('19',1),('17',1),('17',1)],
        [('0',0.33),('29',1),('29',1),('29',0.66)],
        [('0',0.66),('39',1),('39',1),('39',0.33)],
        [('60',3)]
    ],
    [
        [('17',1),('19',1),('111',1)],
        [('0',0.33),('29',1),('29',1),('29',0.66)],
        [('0',0.66),('39',1),('39',1),('39',0.33)],
        [('60',3)]
    ],
    [
        [('112',1),('112',1),('112',1)],
        [('0',0.33),('29',1),('29',1),('29',0.66)],
        [('0',0.66),('39',1),('39',1),('39',0.33)],
        [('60',3)]
    ],
    [
        [('112',1),('111',1),('110',1)],
        [('0',0.33),('29',1),('29',1),('29',0.66)],
        [('0',0.66),('39',1),('39',1),('39',0.33)],
        [('60',3)]
    ],
    [
        [('19',1),('19',1),('19',1)],
        [('0',0.33),('25',1),('25',1),('25',0.66)],
        [('0',0.66),('36',1),('36',1),('36',0.33)],
        [('50',3)]
    ],
    [
        [('19',1),('17',1),('15',1)],
        [('0',0.33),('25',1),('25',1),('25',0.66)],
        [('0',0.66),('36',1),('36',1),('36',0.33)],
        [('50',3)]
    ],
    [
        [('14',1),('14',1),('14',1)],
        [('0',0.33),('24',1),('24',1),('24',0.66)],
        [('0',0.66),('32',1),('32',1),('32',0.33)],
        [('52',3)]
    ],
    [
        [('14',1),('15',1),('12',1)],
        [('0',0.33),('24',1),('24',1),('24',0.66)],
        [('0',0.66),('32',1),('32',1),('32',0.33)],
        [('52',3)]
    ],
    [
        [('10',1),('10',1),('10',1)],
        [('0',0.33),('20',1),('20',1),('20',0.66)],
        [('0',0.66),('31',1),('31',1),('31',0.33)],
        [('42',1),('52',1),('64',1)]
    ],
    [
        [('10',3)],
        [('20',3)],
        [('30',3)],
        [('60',3)]
    ]
]
if __name__ == '__main__':
    play(romance)

多个语音生成谱代码

import matplotlib.pyplot as plt
import librosa
import numpy as np
from scipy.io import wavfile
from collections import Counter
def tian_chong(j,a,b,f):
    # x = 0.9 * np.sin(np.linspace(a, b, j)) + 0.1 * np.sin(np.linspace(np.pi, f * np.pi,j))
    x = 0.9 *np.sin(np.linspace(a, b, j))
    return x

def fen_jie(radio):
    x_index = np.where((radio[1:] / (radio[:-1] + 0.0000001)) < 0)
    # 相邻穿过0点位置的间隔
    x_index_list = np.array([j - i for i, j in zip([0] + x_index[0].tolist(), x_index[0].tolist() + [radio.size])])
    # 翻倍
    # x_index_list*=5

    x_index_list_h = [max(np.abs(radio[i:j])) if radio[i:j].size!=0 else 0 for i, j in
                      zip([0] + x_index[0].tolist(), x_index[0].tolist() + [radio.size])]
    return  x_index_list,x_index_list_h
def huan_yuan(x_index_list,x_index_list_h):


    res = np.hstack([x_index_list_h[i] * tian_chong(j,0, np.pi ,22) if i % 2 == 0 else
                     x_index_list_h[i] * tian_chong(j,np.pi,2 *np.pi, 22) for i, j in
                     enumerate(x_index_list)])
    return res
import os
filename_list=os.listdir("2500中文常用字发音")
reset=[]
for name in filename_list:
    radio,sample=librosa.load("2500中文常用字发音/{}".format(name),16000)
    # radio1,sample1=librosa.load("160_1_recorded2_041_fast.wav",16000)
    # radio=radio[500:3000]

    x,h=fen_jie(radio)

    # x=x**2 事实证明  间隔之间的比值 决定了内容
    # x1,h1=fen_jie(radio1)

    # 连续间距变化小于3的 np.abs(x[1:]-x[:-1])<3
    # reset +=x.tolist()
    # res=huan_yuan(x,h)
    x[x>60]=0
    z=x*h
    z[z<1]=1
    # 求几弦
    xian=np.floor(59 / z) // 10
    xian+=1
    # 求几品
    pin=np.floor(59 / z) % 10
    pin[pin==0]=10
    plt.plot([i for i in range(x.size)],xian)
    plt.plot([i for i in range(x.size)],pin)
    plt.pause(0.001)
    plt.cla()

if __name__ == '__main__':
    pass


整体代码

import numpy as np
from scipy.io import wavfile
import librosa

SPEED = 80  # 用每分钟节拍数表示弹奏速度
FRAME_RATE = 44100  # 采样速率(44100为CD音质,22050为调频广播音质)
STEREO = True  # 立体声(双声道)

# 生成吉他音色包络线
x = np.linspace(0, 3 * np.pi, 2 * int(FRAME_RATE * 60 / SPEED), endpoint=False)
y1 = 1 - x / (10 * np.pi) + (1 - x / (6 * np.pi)) * np.sin(x) * 0.5
x = np.arange(6 * int(FRAME_RATE * 60 / SPEED)) / int(FRAME_RATE * 60 / SPEED)
y2 = 0.7 * np.exp(-x)
GUITAR_EFFECT_ARRAY = np.hstack((y1, y2))


def get_frequency(pos):
    """返回指定弦品pos的频率"""

    fs = (329.6, 246.9, 196.0, 146.8, 110.0, 82.4)
    if pos[0] == '0':
        return 0
    else:
        return fs[int(pos[0]) - 1] * pow(2, int(pos[1:]) / 12)


def get_wave(f, beat):
    """返回指定频率和节拍数的波形数据"""

    data = list()
    duration = beat * 60 / SPEED
    sample_num = int(duration * FRAME_RATE)

    for k, p in [(1, 0.4), (2, 0.3), (3, 0.2), (4, 0.1)]:
        x = np.linspace(0, 2 * duration * f * k * np.pi, sample_num, endpoint=False)
        y = np.sin(x) * p
        data.append(y)

    return guitar_effect(np.sum(np.dstack(data)[0], axis=1))


def guitar_effect(data):
    """将等幅声波变成吉他音色的声波数据"""

    return data * GUITAR_EFFECT_ARRAY[:data.shape[0]]


def play(melody):
    """弹奏吉他谱,若wave_file存在,同时生成.wav文件"""

    data = list()
    for section in melody:
        data_section = list()
        for cord in section:
            data_cord = list()
            for pos, beat in cord:
                f = get_frequency(pos)
                dw = get_wave(f, beat)
                data_cord.append(dw)
            data_cord = np.hstack(data_cord)
            data_section.append(data_cord)

        d = data_section[0]
        for i in range(1, len(data_section)):
            if d.shape[0] > data_section[i].shape[0]:
                d[:data_section[i].shape[0]] += data_section[i]
            else:
                data_section[i][:d.shape[0]] += d
                d = data_section[i]
        data.append(d)

    data = np.hstack(data)
    data = data * 20000 / data.max()
    data = data.astype(np.int16)

    if STEREO:
        blank = np.zeros(int(0.006 * FRAME_RATE), dtype=np.int16)
        d_left = np.hstack((data, blank))
        d_right = np.hstack((blank, data))
        data = np.dstack((d_left, d_right))[0].ravel()
        wavfile.write("160_1_recorded2_001_normal_copy.wav",  44100, data)





def tian_chong(j,a,b,f):
    # x = 0.9 * np.sin(np.linspace(a, b, j)) + 0.1 * np.sin(np.linspace(np.pi, f * np.pi,j))
    x = 0.9 *np.sin(np.linspace(a, b, j))
    return x

def fen_jie(radio):
    x_index = np.where((radio[1:] / (radio[:-1] + 0.0000001)) < 0)
    # 相邻穿过0点位置的间隔
    x_index_list = np.array([j - i for i, j in zip([0] + x_index[0].tolist(), x_index[0].tolist() + [radio.size])])
    # 翻倍
    # x_index_list*=5

    x_index_list_h = [max(np.abs(radio[i:j])) if radio[i:j].size!=0 else 0 for i, j in
                      zip([0] + x_index[0].tolist(), x_index[0].tolist() + [radio.size])]
    return  x_index_list,x_index_list_h
def huan_yuan(x_index_list,x_index_list_h):


    res = np.hstack([x_index_list_h[i] * tian_chong(j,0, np.pi ,22) if i % 2 == 0 else
                     x_index_list_h[i] * tian_chong(j,np.pi,2 *np.pi, 22) for i, j in
                     enumerate(x_index_list)])
    return res



radio,sample=librosa.load("2500中文常用字发音/鼠1627285493.wav",16000)

x,h=fen_jie(radio)


x[x>60]=0
z=x*h
z[z<1]=1
# 求几弦
xian=np.floor(59 / z) // 10
xian+=1
# 求几品
pin=np.floor(59 / z) % 10
pin[pin==0]=10
# 默认节拍为1
pu=[]
for one_x ,one_p in zip(xian,pin):
    pu.append(("{}{}".format(int(one_x),int(one_p)),0.33))

pu=pu[982:1189]
if __name__ == '__main__':
    play([[pu]])



猜你喜欢

转载自blog.csdn.net/weixin_32759777/article/details/123623204