吉他谱生成参考
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]])