幻魔ナイトブログ

主に絵、音楽、プログラミングなどについて書きます。

Music21 4章 リスト、ストリーム、出力

f:id:MahiroN:20200822135636p:plain:w450

Streamとはなんでしょう?英単語で習った時は「小川」でしたね。
正確には小川などの「流れ」を指します。
公式ドキュメントは以下。

User’s Guide, Chapter 4: Lists, Streams (I) and Output — music21 Documentation

Noteオブジェクトを配列として扱う

第3章までが1つの音について話題であったのに対して、第4章はNoteオブジェクトを「リスト」化し「流れ」にした本格的な楽譜について扱います。
面白くなってきましたね。

まずC4とF#4の2つの音を作成します。

>>> from music21 import *
>>> note1 = note.Note("C4")
>>> note2 = note.Note("F#4")

デュレーションを変更して最初の音符を2分音符に変更します。

>>> note1.duration.type = 'half'
>>> note1.duration.quarterLength
2.0
>>> note2.duration.quarterLength
1.0

step属性を見ることで音名だけを出力することができます。

>>> print(note1.step)
C
>>> print(note2.step)
F

しかし実際の楽譜は沢山の音符の集まりです。全てのNoteオブジェクトの音名を上記のように出力するのは面倒くさいですね。
配列を作成してfor文で出力しちゃいましょう。

# Noteオブジェクトのリストを作成します
>>> noteList = [note1, note2]
>>> print(noteList)
[<music21.note.Note C>, <music21.note.Note F#>]

# for分で出力
>>> for thisNote in noteList:\
... print(thisNote.step)
...
C
F

公式ドキュメントにはfor文の説明が書いてありましたが、割愛します。
正直いうと基礎的なプログラミングの知識をつけてから公式ドキュメントを読むことをお勧めします。
このドキュメントはPythonの説明とmusic21ライブラリの説明がごっちゃになっているため分かり難さがあります。   
  
次は新たな音符を音符を作成した音符のリストに追加しましょう。

# Bフラットの音符を作成 
note3 = note.Note("B-2")

# 音符のリストに追加
noteList.append(note3)

# 配列の長さを表示
len(noteList)

# 音名を表示

appendメソッドについてもPythonのリストオブジェクトが持つリストへの追加メソッドであるため、ここでは深くは言及しません。

Streamオブジェクト

この章の本題であるStreamオブジェクトについての説明となります。 StreamオブジェクトはサブクラスとしてScore、Mesure、Partを持っておりmusic21の基本をなすオブジェクトとなります。

そのほかにmusic21にとって重要なオブジェクトはNote, Chord, Clef, TimeSignatureオブジェクトとなります。

ここでStreamオブジェクトがどのようなものかざっくりと紹介しておくと、Pythonの配列です。 ただし、NoteオブジェクトやChordオブジェクトなどのmusic21のオブジェクトのみを格納できる点が他のPythonオブジェクトと違います。
ただ、配列であるということを覚えておけば、扱いは前節で行ったようにリストとしてのメソッドを使うだけなので楽です。

早速Streamオブジェクトを作ってみましょう。
例によってstreamモジュール(小文字)からStreamオブジェクトを作成します。

stream1 = stream.Stream()

stream1という入れ物ができたので、音符を追加していきましょう。appendメソッドを使用します。

stream1.append(note1)
stream1.append(note2)
stream1.append(note3)

さて、同じ楽譜を繰り返し入力したい場合、何回もappendを使用するのは面倒くさいですね。
repeatAppendメソッドを使用すればもう少し楽に入力することができます。

stream2 = stream.Stream()
n3 = note.Note('D#5') # octave values can be included in creation arguments
stream2.repeatAppend(n3, 4)
stream2.show()

repeatAppendメソッドの第1引数はNoteオブジェクトのインスタンス、第2引数は繰り返し回数です。 上の例ではn3という引数に対してD#の音を格納し、それを4回繰り返しているのです。

さて、ストリームの中にどんな音符が入っているか見るにはどうすれば良いでしょうか?
showメソッドを使用することでストリームを可視化することができます。
主な使い方は

  • 文字として情報を出力したい場合: 引数に「’text’」を渡します。
stream1.show('text')
  • 楽譜として出力したい場合: 引数には何も渡しません。
stream1.show()

ストリームへのアクセス

さて、ストリームはpythonでいうところのリストとほぼ同じようなオブジェクトだという話をしたと思います。
なのでストリームの中を見たい!っとなった時は基本的に配列の中身の取得と同じような手法をとることができます。

ストリームオブジェクトは引き続きstream1を使い続けます。

  • for文で取り出す
for thisNote in stream1:
    print(thisNote.step)
  • インデックス番号でアクセスすることも可能♪
# Noteオブジェクトを表示
stream1[0]

# Noteオブジェクトの中の属性を確認
stream1[-1].nameWithOctave

# 指定したオブジェクトの最初のインデックス番号はindexメソッドで取得可能。これもリストと同じ
note3Index = stream1.index(note3)

# popメソッドも使用可能
stream1.pop(note3Index)

# appendメソッドも使用可能
stream1.append(note3)

getElementsByClass()メソッドを使用したストリームの分離

さて、このお題だけでは何をっているおさっぱりさっぱりですね。
ざっくりいうと要素のタイプやオフセットの長さごとにグループ分けできるらしく、フィルタリングをできるとのことです。
こう言われると何やら便利そうな気がしてきますね。

javascriptSeleniumを勉強した人にとってはとても感覚的にわかりやすいかも知れません。
要するに特定の条件を満たす音符を取得するためのメソッドなのです。 使い方は以下のようになります。

ストリームオブジェクト.getElementByClass 
stream1.getElementsByClass(note.Note):

お問合わせはこちら