Music21
建议配合官方图片食用
音符(Notes)
标准音符的概念被包含在 note
的 Note
对象之中
直接输入 note
便可得到该模块的位置
如果你想知道 note
除了 Note
还包含什么,可以输入 dir(note)
创建音符
让 我们使用 note.Note
创建一个音符
f = note.Note('F5')
音符的属性
F5
是这个音符的音名
通过 .name
.step
和 .octave
可以得到其音名、音级、八度(在第几个八度)信息
f.name f.step f.octave
'F' 'F' 5
.step
得到不包含变化音及八度信息的音名,这里成为音级严格来说并不准确
当然也可以使用 .pitch
直接得到其音名
f.pitch
<music21.pitch.Pitch F5>
使用 .pitch.frequency
得到其频率
f.pitch.frequency
音高698.456462866008
使用 .pitch.pitchClass
同样可以得到其音级(距离同一个八度中 c
的半音数字),使用 .pitch.pitchClassString
则可以得到一个 String
f.pitch.pitchClassf.pitch.pitchClassString type(f.pitch.pitchClassString)
音高5 '5' <class'str'>
在 music21 中,升降分别使用 #
和 -
,我们创建一个新的音符
b_flat = note.Note("B2-")
使用 .pitch.accidental
可获得其属性 (accidental
在音乐中表示变音记号),使用 .pitch.accident.alter
获得其半音变化数量,使用 .pitch.accidental.name
获得其
b_flat.pitch.accidental b_flat.pitch.accidental.alter b_flat.pitch.accidental.name
<accidental flat> -1.0 'flat'
注意,这里是一个浮点数,这意味着 music21 支持四分音符之类现实中通常不使用的东西
此外,并不是每一个音符都有 accidental 的,某些音符会返回 None
我们可以使用一个判断语句来解决:
if d.pitch.accidental is not None:
print(d.pitch.accidental.name)
如果你安装了 MusicXML
阅读器,使用 f.show()
可查看其五线谱
修改音符
使用 .transpose
修改你的音符
d = b_flat.transpose("M3") #将Bb上调大三度,变为D
这种用法并没有改变音符本身,而是返回一个变量
可以使用 inplace=True
进行原地操作
休止符
使用 note.rest
a = note.rest() # 记得加括号
最后提醒一个点,不要使用 note
作为音符的变量
note = note.Note("C4")
音高(Pitch),时值(Duration)
音高
使用 pitch.pitch()
创建一个音高对象
p1 = pitch.Pitch('b-4')
有许多属性和 note
是一样的
pl.octave pl.name pl.pitchClass pl.accidental.alter
4 'B-' 10 -1.0
.transpose()
同样可以使用
.nameWithOctave
和 .midi
pl.nameWithOctave pl.midi
'B-4' 70
这些属性大多数都可以修改
pl.name = "d#"
pl.octave = 3
pl.nameWithOctave
'D#3'
这时 pl 代表的音符已经变为了 D#3
实际上,每一个 Note 对象内部,都有一个 Pitch 对象,我们对 note.Note
做的一切,都可以用 note.Note.pitch
对象代替
一些 note
不支持的属性
csharp.pitch.spanish # 获得其西班牙名称
可以使用一些其他的方法,来更清晰地打印
print(csharp.pitch.unicodeName)
C♯
获得一些同音的方法
print( csharp.pitch.getEnharmonic() )
print( csharp.pitch.getLowerEnharmonic() )
D-4
B##3
时值
任何音符的存在都离不开时值 Duration
创建一个二分音符
halfDuration = duration.Duration('half')
# ‘whole','half','quarter','eighth','16th','32th','64th' 一直到'2048th',虽太小无法在乐谱上无法显示
# 'breve','longa','maxima' 2,4,8个全音
另一种创建方法是说明他有多少个四分音符
dottedQuarter = duration.Duration(1.5)
可以使用 .quarterLength
得到时值是多少个四分音符
还可以使用 Note
创建
c = note.Note("C4", type='whole')
.type
可以得到一般类型,如 'half','quarter'
.dots
可以得到音符有多少个附点
使用 .lyric
添加歌词(具体看文档吧,不具体介绍了)
otherNote = note.Note("F6")
otherNote.lyric = "I'm the Queen of the Night!"
流 (Stream)
我们可以通过列表对 note 等对象进行处理,但是它们对音乐一无所知,因此需要一个类似于列表的对象具有一定“智能”的对象,成为 Stream
流有许多子类 Score
乐谱、Part
声部、Measure
小节
创建流
Stream
中储存的元素必须是 music21 对象,如果想加入不属于 music21 的对象,请将其放入 ElementWrapper
使用 Stream()
创建流,.append()
方法添加元素,.repeatAppend()
方法添加多个相同的音符
stream1 = stream.Stream()
stream1.append(note1)
stream1.append(note2)
stream1.append(note3)
stream2 = stream.Stream()
n3 = note.Note('D#5') # octave values can be included in creation arguments
stream2.repeatAppend(n3, 4)
使用 .show('text')
查看其中的内容及其偏移量(从 0.0 开始,一般 1 个偏移量指一个四分音符的长度)
stream1.show('text')
{0.0} <music21.note.Note C>
{2.0} <music21.note.Note F#>
{3.0} <music21.note.Note B->
流的大部分方法和列表相同,如切片、索引(还可使用 .index()
访问)、pop()
、.append()
、len()
等,并且流中也可以存放列表
按类分离元素
提供一种过滤流以获取所需元素 .getElementByClass()
for thisNote in stream1.getElementsByClass(["Note", "Rest"]):
print(thisNote, thisNote.offset)
<music21.note.Note C> 0.0
<music21.note.Note F#> 2.0
<music21.note.Note B-> 3.0
此外也可使用 .notes
、.notesAndRests
、.pitches
等来进行过滤,直接使用会返回所有,如
stream1.pitches
[<music21.pitch.Pitch D#5>,
<music21.pitch.Pitch D#5>,
<music21.pitch.Pitch D#5>,
<music21.pitch.Pitch D#5>]
for thisNote in stream1.notesAndRests:
print(thisNote)
<music21.note.Note C>
<music21.note.Note F#>
<music21.note.Note B->
通过偏移量分离元素
getElementsByOffset()
sOut = stream1.getElementsByOffset(2, 3).stream()
sOut.show('text')
{2.0} <music21.note.Note F#>
{3.0} <music21.note.Note B->
还有 getElementAtOrBefore()
(某个偏移量及其之前 score = stream.Score()
1),getElementAfterElement()
(某个偏移量之后)
更多功能
.analyze('ambitus')
获得流中的音域范围
.lowestOffset
返回偏移量的最小值
__repr__
.id
,可以自己设定,相当于名字,如
s = stream.Score(id='mainScore')
p0 = stream.Part(id='part0')
p1 = stream.Part(id='part1')
.duration
储存 Duration 对象的属性
小节 (Measure)
可以使用 corpus
访问大量的乐谱,使用 Parse()
从语料库中解析出 Score
(一种流的子类)
sBach = corpus.parse('bach/bwv57.8')
它包含一个 Metadata
对象、一个 StaffGroup
对象和四个 Part
对象。
可以使用 measures()
或 measure()
获取多个或一个小节,前者获取整个乐曲所有 Part
的小节,后者必须对一个 Measure
对象
然而一个问题是,这与使用 getElementsByClass(stream.Measure)
并不相同,因为在乐曲中存在小节并不连续的情况
递归方法
.recurse()
可以访问流中的每一个元素 ,若任何子元素也是流,他将访问该流中的每一个元素
他会返回一个生成器,使用循环来访问每一个元素
recurseScore = s.recurse()
recurseScore
<music21.stream.iterator.RecursiveIterator for Score:mainScore @:0>
for el in s.recurse():
print(el.offset, el, el.activeSite)
0.0 <music21.stream.Part part0> <music21.stream.Score mainScore>
0.0 <music21.stream.Measure 1 offset=0.0> <music21.stream.Part part0>
0.0 <music21.note.Note C> <music21.stream.Measure 1 offset=0.0>
4.0 <music21.stream.Measure 2 offset=4.0> <music21.stream.Part part0>
0.0 <music21.note.Note D> <music21.stream.Measure 2 offset=4.0>
0.0 <music21.stream.Part part1> <music21.stream.Score mainScore>
0.0 <music21.stream.Measure 1 offset=0.0> <music21.stream.Part part1>
0.0 <music21.note.Note E> <music21.stream.Measure 1 offset=0.0>
4.0 <music21.stream.Measure 2 offset=4.0> <music21.stream.Part part1>
0.0 <music21.note.Note F> <music21.stream.Measure 2 offset=4.0>
大多数过滤方法也可以用于该生成器
扁平化流
.flat
可以将嵌套流打平,并赋予新的 offset
和弦 (Chord)
创建和弦
cMinor = chord.Chord(["C4","G4","E5-"]) # 通过音名的列表创建
d = note.Note('D4')
fSharp = note.Note('F#4')
a = note.Note('A5')
dMajor = chord.Chord([d, fSharp, a]) # 添加已有的音符
e7 = chord.Chord("E4 G#4 B4 D5") # 通过带有空格的字符串创建
es = chord.Chord("E- G B-") # 如果所有音符的都在一个八度内,则不需要八度信息
功能
Chord
和 Note
对象都是 GneralNote
对象的子类,因此大部分 Note 的属性,Chord 都能使用
其中,音高由 .pitch
被替换为 .pitches
一些其他功能
cMinor.isMinorTriad() # 是否是小三和弦
cMinor.isMajorTriad() # 是否是大三和弦
cMinor.inversion() # 是否处于转位状态
cMinor.add() # 添加音符
cMinor.remove() # 移除音符
cClosed = cMinor.closedPosition() # 封闭和弦,不会该改变原对象
semiClosedPosition() # 不太懂
cn1 = cMinor.commonName # 得到和弦的名字
fMajor.fullName # 包含step和时值
fMajor.pitchedCommonName # 加入了pitch信息
和弦和音符一样可以添加到流之中
加载文件
使用 corpus.parse()
从语料库加载文件
使用 converter.parse()
从本地磁盘或网络加载文件
如果文件名没有后缀或者后缀有误,可以使用 format="FORMAT"
music21 会在第一遍读取文件后保存优化版本,若下次读取时检测到没有更改文件,那么速度将会提升 2 到 5 倍(大概是通过检查文件修改时间是否变动,可以使用 forceSource=True
来保证重新加载原文件)
使用 converter.Converter().subconvertersList('input')
得到其可以读入的所有格式
使用 converter.Converter().subconvertersList('output')
得到其可以写的所有格式
其可以使用的文件格式有 Humdrum
、MusicXML
、MusicXML
、Musedata
、MIDI
等
Chordify
Chordify ,顾名思义,ify 后缀通常表示使动,即为使…变为和弦,可翻译为 和弦化
b = corpus.parse('bwv66.6') # 读取乐谱,该乐谱有很多个声部
bChords = b.chordify() # 和弦化,多个声部变为一个和弦
看不懂了…