🎵

Pythonで音符やコード進行の音声波形を扱うライブラリを作った

2023/04/24に公開

munotes

タイトルにあるようなライブラリです。

たとえば、「ド」とか「C#7」みたいな音やコードの波形(sin波とか矩形波とか)が欲しい、という場面で使えます。

インストール

pip install munotes

対応しているPythonのバージョンは3.7以上です。

使い方

このライブラリはいくつかのクラスを提供します。
音符や和音を扱うクラスと、それらを並べてシーケンスとして扱うクラスがあります。

mn.Note

単音を扱うクラスです。音名を入力し、オブジェクトを生成します。

import munotes as mn
note = mn.Note("C4")
print(str(note)) # C4

音名とオクターブを分けた入力や、midiノートナンバーでの指定も可能です。

note = mn.Note("C", 4)
note = mn.Note(60)

このオブジェクトは以下のような属性を持ちます。

print(note.name) # C
print(note.octave) # 4
print(note.num) # 60
print(note.freq) # 261.6255653005986

Note.freqから得られる周波数はA4=440Hzを基準としたものです。生成される波形に影響を与えます。以下のように変更することができます。

note.tuning(270)
print(note.freq) # 270

A4を基準とした指定もできます。

note.tuning(441, stand_A4=True)
print(note.freq) # 262.2201688581

Note.freqNote.A4を直接変更しても問題なく動きます。

note.freq = 270
note.A4 = 441

transpose()メソッドで音を平行移動できます。

note.transpose(1)
print(note.name) # C#


では、波形を生成していきましょう。以下のメソッドを使用します。

  • sin(): sin波
  • square(): 矩形波
  • sawtooth(): ノコギリ波

引数は以下の二つです。

  • sec: 秒数(デフォルト=1)
  • sr: サンプリングレート(デフォルト=22050)

numpyの配列が返ってきます。

import matplotlib.pyplot as plt
note = mn.Note("C4")
sin = note.sin(sec=1, sr=22050)
square = note.square()
sawtooth = note.sawtooth()
fig, (ax1, ax2, ax3) = plt.subplots(3, 1)
ax1.plot(sin[:400])
ax2.plot(square[:400])
ax3.plot(sawtooth[:400])

waveforms

square()sawtooth()は固有の引数を1つ持っています。

square = note.square(duty=0.1)
sawtooth = note.sawtooth(width=0.5)

waveforms2

render()メソッドで任意の波形を生成することもできます。

import numpy as np
y = note.render(lambda t: np.sin(t) + np.sin(2 * t))
plt.plot(y[:400])

sin2

play()メソッドを使うと、notebookに埋め込める音声を直接取得できます
play


mn.Notes

複数のNoteをまとめて和音として扱うクラスです。

notes = mn.Notes(
    mn.Note("C4"),
    mn.Note("E4"),
    mn.Note("G4")
)
print(notes.names) # ['C', 'E', 'G']

Note(やNotes)同士を足すことでも和音を生成できます。

notes = mn.Note("C4") + mn.Note("E4") + mn.Note("G4")
print(notes.names) # ['C', 'E', 'G']

基本的な使い方(属性・メソッド)はNoteと同じです。以下のメソッドで波形を扱うことができます。

  • Notes.sin()
  • Notes.square()
  • Notes.sawtooth()
  • Notes.render()
  • Notes.play()


mn.Chord

コードを扱うクラスです。入力されたコード名から、コードを構成する音符でのNotesオブジェクトを生成します。

chord = mn.Chord("C#m7", octave=4)
print(chord.names) # ['C#', 'E', 'G#', 'B']

octaveは生成する波形に影響を与えます。デフォルトは4です。
基本的な使い方はNoteと同じです。

transpose()を使用するとコード名も変わります。

chord.transpose(1)
print(chord.name) # Dm7


mn.Track

複数の音符を並べてシーケンスとして扱うクラスです。
音符と長さのタプルを一つの音符として扱い、それらをリストで渡すことでTrackオブジェクトを生成します。

track = mn.Track([
    ("C4", 1),
    ("E4", 1),
    ("G4", 1)
])

ド→ミ→ソが1秒ずつ鳴る、合計3秒の音符列が生成されます。

タプル内の音符として、NoteNotesオブジェクトまたは音名を表す文字列が入力可能です。
長さの単位は秒になっていますが、引数unitを指定することで変更可能です。以下の中から選択できます。

  • s: 秒(デフォルト)
  • ms: ミリ秒
  • ql: QuarterLength(4分音符)

qlを選択した場合はbpmの指定が必要になります。

track = mn.Track([
    ("C4", 1),
    ("E4", 1),
    ("G4", 1)
], unit="ql", bpm=120)

Track.sequenceから音符を取り出せます。

print(track.sequence) # [(Note C4, 1), (Note E4, 1), (Note G4, 1)]

append()メソッドで音符を追加できます。音符と長さのタプルを好きなだけ与えます。

track.append(("C5", 1), (mn.Chord("C"), 2))
print(track.sequence) # [(Note C4, 1), (Note E4, 1), (Note G4, 1), (Note C5, 1), (Chord C, 2)]

その他の使い方はNoteと同じです。


mn.Stream

複数のTrackをまとめて扱うクラスです。所謂polyphonicな音楽になりますね。
Trackオブジェクトをリストで渡すことでStreamオブジェクトを生成します。

melody = mn.Track([
    ("C4", 1),
    ("D4", 1),
    ("E4", 1)
])

chords = mn.Track([
    (mn.Chord("C"), 3),
])

stream = mn.Stream([melody, chords])

使い方はTrackと同じです。


基本的な機能は以上になります。

Discussion