发现一个非常有趣冷门的GitHub项目开源项目,可以通过ChatGPT生成乐谱,然后通过Python代码生成音乐,项目地址:
https://github.com/jiran214/GPT-Musician
目前只有几个star,代码也非常少,主要是思路清奇,灵感来源推特:
这位推特用户分享了一种利用开源数据集微调了 Llama 2 模型,以生成音乐乐谱文本,不使用音频物理数据或 MIDI 数据数据源传统方法进行预训练,而是采用了一种称为 ABC 记谱法的方式微调训练去生成乐谱。
ABC 记谱法是一种简单易学的音乐记谱方法,通常用于传统音乐和民间音乐的记录和分享。它使用基本的字母、数字和符号来表示音乐的音高、音长和节奏。每个音符都由一个字母表示,而音符的持续时间则由字母后的数字和符号表示。
以下是一些ABC记谱法的字符符号含义解释:
-
小写字母 a-g:表示音符,分别对应音阶的音符,例如 a 表示 La,g 表示 Sol。
-
大写字母 A-G:表示高音区的音符,相对于小写字母音符高一个八度。
-
符号 `, ':用于表示音符的八度,例如 a' 表示 La 的高音。
-
数字 1-9:表示音符的持续时长,数字越大表示音符越长,通常以1为最短时长。
-
/
:表示分音符(半音符)。
-
-
:表示休止符,用于表示音符的间隔或停顿。
测试
首先需要告诉ChatGPT 如何使用这个ABC记谱法,我按照项目教程改造了一点,prompt提示词如下:
SYSTEM = """# 角色
你是一个才华横溢的**流行音乐创作大师**,擅长用ABC记谱法,
## 技能:
### 技能 1:打造音乐结构
- 掌握并运用流行音乐常见的乐曲形式:前奏、主歌1、副歌1、主歌2、副歌2、中段(独奏或桥梁)、副歌3以及尾声。
- 根据用户输入决定ABC内容,包含X T M K X L P标记
- 根据输入,选择和主题匹配的套路和弦、调性、标题、情绪、速度、节奏。
### 技能 2:创作动人旋律
- 多使用七和弦和分解和弦
- 旋律好听,节奏要跟随发展产生较大的变化
- 副歌部分用简洁且重复的旋律,让人忍不住想一遍遍重复听
## 要求:
- M标记的拍数严格等于每个小节拍数,比如当M:4/4时,每小节的拍数都为4
- 音符后面的数字代表持续时长,控制每小节的拍数符合M的要求
- 直接生成乐谱出来,不要描述其它的术语
## 输出格式:
- 和弦标记要用引号
- 在ABC乐谱中,用P:标记段落,段落之间用换行分隔
- 使用ABC谱输出乐曲内容,确保其格式完全符合ABC标准。
- 用markdown的代码块格式输出乐谱,方便用户阅读和理解。
"""
接下来就可以问问题了,我这里使用免费coze 的ChatGPT4的能力,效果非常不错(访问:coze.com):
然后这里我就直接把代码亮出来,也不算太长,把作者代码精简了很多,我这里是直接把乐谱复制到代码里面来了,作者在代码里调用了OpenAI的能力可以直接输入描述想要什么内容的音乐直接生成wav音频文件:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
import time
# 需要手动安装这个包 pip install symusic
# 一个用于处理音乐符号的 Python 库,它提供了读取、写入和操作音乐符号生的功能
from symusic import Score, Synthesizer, dump_wav
def process(content):
abc_notation = re.search(r'```.*(X:.*)```', content, flags=re.S) or re.search(r'```.*(T:.*)```', content, flags=re.S)
if not abc_notation:
print('解析失败!😭')
abc_notation = abc_notation.group(1)
if 'X:' not in abc_notation:
abc_notation = f'X:1\n{abc_notation}'
title = re.search(r'T:(.+?)\n', abc_notation, flags=re.S)
title = (title and title.group(1)) or int(time.time())
filename = f"{title}.wav"
abc_notation = abc_notation.strip().replace('\n\n', '\n').replace('min', 'm')
s = Score.from_abc(abc_notation)
audio = Synthesizer().render(s, stereo=True)
dump_wav(filename, audio, sample_rate=44100, use_int16=True)
return filename
if __name__ == '__main__':
content = '''```abc
X:1
T:梦之翼
M:4/4
K:D
L:1/8
P: Intro
"D"D2 F2 A2 d2 | "A"c2 A2 F4 | "Bm"B2 d2 f2 b2 | "G"g2 B2 d4 |
"D"D2 F2 A2 d2 | "A"c2 A2 F4 | "Bm"B2 d2 f2 b2 | "G"g2 B2 d4 |
P: Verse 1
"D"d2 d2 "A"c2 A2 | "Bm"B2 "A"A2 "G"g4 | "D"d2 d2 "A"c2 A2 | "Bm"B2 "A"A4 |
"D"d2 d2 "A"c2 A2 | "Bm"B2 "A"A2 "G"g4 | "D"d6 "A"A2 | "Bm"B2 "A"A2 "G"g4 |
P: Chorus
"G"g2 f2 e2 d2 | "A"a2 a2 a4 | "D"d2 f2 "A"a2 g2 | "G"f4 e4 |
"D"d2 "A"c2 "Bm"B2 A2 | "G"G2 A2 B4 | "A"a2 "G"g2 "D"f2 e2 | "A"A4 A4 |
P: Verse 2
"D"d2 d2 "A"c2 A2 | "Bm"B2 "A"A2 "G"g4 | "D"d2 d2 "A"c2 A2 | "Bm"B2 "A"A4 |
"D"d2 d2 "A"c2 A2 | "Bm"B2 "A"A2 "G"g4 | "D"d6 "A"A2 | "Bm"B2 "A"A2 "G"g4 |
P: Chorus
"G"g2 f2 e2 d2 | "A"a2 a2 a4 | "D"d2 f2 "A"a2 g2 | "G"f4 e4 |
"D"d2 "A"c2 "Bm"B2 A2 | "G"G2 A2 B4 | "A"a2 "G"g2 "D"f2 e2 | "A"A4 A4 |
P: Bridge
"D"D4 "A"A4 | "Bm"B4 "G"G4 | "D"d4 "A"c4 | "Bm"b2 "A"a2 "G"g4 |
"D"D4 "A"A4 | "Bm"B4 "G"G4 | "D"d4 "A"c4 | "Bm"b2 "A"a2 "G"g4 |
P: Final Chorus
"G"g2 f2 e2 d2 | "A"a2 a2 a4 | "D"d2 f2 "A"a2 g2 | "G"f4 e4 |
"D"d2 "A"c2 "Bm"B2 A2 | "G"G2 A2 B4 | "A"a2 "G"g2 "D"f2 e2 | "A"A4 A4 |
```'''
process(content)