好玩 | Python 弹琴 Rusty Lake Family Tune
0. 安装库
-
安装 alive-progress: 显示音乐进度进度条
pip install alive-progress
-
安装 pyaudio: 播放每个音键wav文件
- pip install pyaudio
在安装的setup部分可能会报错, 导致不能装上 - 跳转到 下载连接, 下载对应python版本的 pyaudio whl文件, 然后 pip install xxxxx.whl 安装刚刚下载的 whl 文件
?
1. 准备乐谱
乐谱准备在一个 str.txt里, 形如: 每一行代表一个时间点: | 左边代表时间点, | 右边代表这个时间点要弹的音键 ?
2. 将乐谱转成列表存储在 pkl文件
import pickle
songName = 'RustyLake FamilyTune'
with open(f'./{songName}/str.txt', 'r') as rf:
lines = rf.readlines()
rf.close()
musicList = []
for line in lines:
t, w = line[:-1].split('|')
musicList.append((float(t), w))
with open(f'./{songName}/musicList.pkl', 'wb') as wf:
pickle.dump(musicList, wf)
wf.close()
3. 编写播放wav文件函数
这个函数基本不用改, 只需要传入wav文件的名字即可开始播放
def playWav(wav):
filepath = 'E:/Python program/2_PythonPiano/keys/'
path = filepath + wav + '.wav'
chunk = 1024
file = wave.open(path, "rb")
player = pyaudio.PyAudio()
stream = player.open(format=player.get_format_from_width(file.getsampwidth()),
channels=file.getnchannels(),
rate=file.getframerate(),
output=True)
data = file.readframes(chunk)
while len(data) > 0:
stream.write(data)
data = file.readframes(chunk)
file.close()
?
4. 根据乐谱顺序播放wav文件
def playMusic(name):
with open(f'./{name}/musicList.pkl', 'rb') as rf:
musicList = pickle.load(rf)
rf.close()
with alive_bar(len(musicList)) as bar:
for i in range(len(musicList)):
bar()
if i + 1 != len(musicList):
sleepTime = musicList[i + 1][0] - musicList[i][0]
else:
sleepTime = 0
threads = []
for w in musicList[i][1].split(','):
threads.append(
threading.Thread(target=playWav, args=(w,))
)
for t in threads:
t.start()
time.sleep(sleepTime)
?
5. 效果
PyPiano - RustyLake FamilyTune
?
6. 乐谱参考
感谢 bilibili up主@CENNHM 乐谱和代码部分参考 来自 up主@CENNHM 博客中的代码在原有代码基础上进行了修改:
- 线程顺序添加, 避免一开始创建太多线程导致系统调度卡顿
- 对乐谱的数据结构进行修改
|