😽

あらゆる理論で音楽を作成・分析できるPythonライブラリ Neuma を作成する (1) - Neuma の根幹 -

2023/08/03に公開

西洋の音階に縛られない音楽を作ったり分析したりしたーい!
ということで、Pythonで音楽を作成・分析できるライブラリを自作しています。

まだ制作途中で、とある理由から当分公開する予定ではありませんが、アイデアまとめのためにも記事にしておきます。
いずれ、オープンソースとして公開する予定です。

動機

なんで思いついたか 忘れました
ただ、 「既存の西洋音楽の音階に縛られたツールって随分多いよな」とは前から思っていました。
具体的には、以下のようなものです。

  • DAW
  • MIDI
  • MusicXML

などなど。
これら全て、西洋音楽の「ドレミファソラシ」の 7音階 を前提としています。
まあ、そういう音楽がメジャーなので当然と言えば当然ですが。

ここでいう「西洋音楽の音階」とは

古典クラシックから続く、「ドレミファソラシ(もしくはそれに相当する音階)」のことです。
これに同音異名の音を含めた12音階を前提としています。

現在、主流なのはその12音階を用いた 12平均律 です。
音数もそこまで多くなく、どの音の幅も均等なので、キーを変えやすく扱いやすいです。

しかし、西欧音楽の音階がメジャーだということは、マイナーな音階もあるわけです。
有名どころでは、日本の音階とよく言われる(けどただの総称の) 四七抜き音階 があります。

四七抜き音階とは

ドレミファソラシの最初から 4 番目と 7 番目の音を抜いた音階です。
つまり、ドレミソラの5音階ですね。
日本っぽい音階と言われるのは、日本特有の音階に近いからですね。
四七抜き音階といえば、アイルランドの民謡にもみられるので、日本特有というわけではないです。
そもそも、「ドレミファソラシから4番目と7番目の音を 抜く」と言っている時点で、西洋音楽の音階を前提としています。

あとは、Python 使ってなんかしたいってのもありました。
最終的に AI 的なもの作れたら楽しそうだなぁとか思ってます。

詳細

名前

「Neuma」といいます。
読み方は「ネウマ」です。
「Neuma Explores Unleashed Music Arts」の略で、既存の音楽理論や体系にとらわれず、自由に音楽を作成・分析できるようになることを目指して名付けました。

余談

Wine という Mac で Windows ソフトウェアを使えるようにできるツールがあるんですが、それの正式名称が、「Wine Is Not an Emulator」なんですよね。
このネーミングセンス、好きです。
だから、Neuma という名前を付けた時に、このネーミングセンスを真似てみました。
自分では思いつかなかったので ChatGPT と相談したら思ったより壮大なのが出てきてビビっています。
ちなみに、評価してもらった結果はこちらです。

「やるじゃーん」って感じです。
Arts に関してはそこまで考えてはないのですが、詳しいライブラリの説明せずに、名称だけでこれですからね。
すごいもんですよ。
むしろ「名は体を表す」って言葉があるくらいなので、名前だけでここまで表現できるものを出してきた ChatGPT がすごいのか。
ただ、どうしても各単語の頭をとって略称にするというのを理解できていないのかなと。
名前を考えてもらう時もわざわざ「Neuma E-- U-- Music A--」って指定して出してきた候補の2/5がその通りだったくらいなので。

基本方針

次に基本方針を説明していきます。
根本となる方針は以下の通りです。

  • 人間の感覚に近い 表現をする
  • 既存の理論を適用できるほどの 拡張性 を持つ

一つ目はそのままの意味です。
音楽は 人間が聴くものなの で、人間の感覚に近い表現をすることが重要だと考えています。
これで、「音楽の分析時に感覚に近い分析ができるんじゃないかなあ」という希望的観測です。

二つ目はこのライブラリを使用する側のことを考えたものです。
なんだかんだ既存の音楽理論はとても洗練されています。
これを完全に使えないというのは、あまりにも勿体無いです。
また、自分オリジナルの理論で作ってしまっては新しい理論を作った時や理論を修正した時に、 ライブラリを修正しなければならなくなります
せっかくオブジェクト指向の Python 使うわけですし、どんな理論でも適用できる拡張性が欲しいです。

音階の表現

音階の表現には、 音程 を用います。
音程とは、音の高さの差のことです。
よく、音程を音高(音の高さ)と間違えている人がいるというか、ほとんどの人が勘違いしていますが違います。
だから、「音程が低い」とか言ってる人は勘違いしている人です。(世のほとんどの人はそうらしいですね)

余談は置いておいて、音程を基準にするというのは、多くの人が音楽を感じる感覚に近いと思っています。
多くの人は絶対音感なんて持っていません。
僕も持っていません。
大抵わかるのは基準より高いか低いか、わかってもどれくらい高いか低いかであって、基準の音を正確に当てることはできません。

だからこそ、音の幅 である音程を表現に用います。

音程の話

DAW に親しんでいる人は半音基準の音の高さの差に慣れ親しんでいると思います。
しかし、実際の音楽では、全ての音が使われているわけではありません。
中心的に使われている音があって、そこから少しずれている音が使われているわけです。
だから、古典的な音楽理論において「ドとミ」の音程と「ドとミ#」の音程は同じ「3度」の音程です。

違和感を感じた人に向けて

結局、西洋の音楽理論じゃねえかと思ったと思います。
そうです。
ただ、なんだかんだ音楽って離散的な音の集まりなわけです。
離散的な音の集まりではあるんだけども、間の音を使い時もありますよね。
そういう時のための拡張性を持たせつつ、離散的な感覚を実装するために、音程を使うことにしました。

じゃあ基準をどこにするかというと、 オクターブの中の一番低い音 です。
例えば、「ドレミファソラシ」の場合はドです。
本当はどこ基準でもいいです。
ラを基準にしてもいいんですけど、一番低い音にするとわかりやすく、オクターブを別の変数として持つようにすると音程の変数が自然数になるので、扱いやすいです。

問題はド#とかレbとかのピアノでいうところの黒鍵の音です。
これの表現には別の 音のズレ というパラメータを用います。
例えば、ド#の場合は「上にズレる」、レbの場合は「下にズレる」です。

オクターブの基準は 0 です。
0です。(2回目)
これは、どこでもいいのでわかりやすいところにしたという感じです。
後々少し面倒にはなりましたが、まあいいでしょう。

音符の長さの表現

音符の長さの表現には、有理数 を用います。
基準は 1小節 です。
4分音符を基準にする方法もありますが、曲の分割の単位としては小節の方がわかりやすいと思ったので、この基準を採用します。
有理数を用いして、1小節のうち、どれくらいの時間を占めるか で音符の長さを表現します。

まとめ

以上です。
実際、すでにもっと実装していますが、このライブラリの根幹的な部分はこの音階の表現と音符の長さの表現のみです。

実装

この実装については非常にシンプルなので、コードを貼り付けます。

note.py
from dataclasses import dataclass
from fractions import Fraction


@dataclass(frozen=True)
class Note:
    """音符"""

    tone: int
    duration: Fraction = Fraction(1)
    diff: Fraction = Fraction(0)
    octave: int = 0


@dataclass(frozen=True)
class Rest:
    """休符"""

    duration: Fraction = Fraction(1)

まず、このクラスはデータを格納するだけのクラスです。
dataclass デコレーターを使って擬似イミュータブルにしています。
詳しい解説は dataclass に関する記事や公式ドキュメント[1]に譲りますが、frozen=True とすることで、擬似イミュータブルになります。
「擬似」と言っているのは、やろうと思えば書き換えることができるからです。
ただ、その方法は大分明示的なので、意図せず書き換えることはまずないです。(別のモジュールで複製時などに使用しています。)

音程を持つ Note クラスと、音程を持たない Rest クラスがあります。
Rest クラスは休符ですね。
後々の計算の都合上、休符がないと再生位置の計算ができなかったので……
それから、実際に再生するときは無視する都合上、 楽譜上で音符に付随しない情報のタイミング を載せられて、なんだかんだ都合がいいです。

tone はそのまま音程で、自然数が入ります。
型ヒントで int とし、マイナス値やオクターブ超えの音程の値は このクラスでは制限しません

duration は音符の長さで、Fraction クラスを使って、1小節内の長さを表現しています。

diff は音程のズレで、Fraction クラスを使って、音程のズレを表現しています。

octave はオクターブで、整数が入ります。
こちらは仕様上マイナス値を許容します。

ここから

ここからは、この Note クラスを元に、音を表示・再生するコードを書いていきました。
現状、音を 7音階で 表示するコードは完成して、n平均律の音高で 基本波形での再生はできるようになっています。
今作っているのはシンセサイザーです。
これができたら、いくつか楽器とエフェクターを作って、それらを組み合わせて曲を作ることができるようになります。
そしたら、分析するという本編の方に向かいたいと思います。
(ただ、分析するには既存の曲の読み込みをしたいので MusicXML とかの読み込みをするコードを書かないといけないですね……)

次の記事では、音を表示する方法について書いていきます。

次回 ->

脚注
  1. dataclasses --- Python 3.11.4 ドキュメント ↩︎

Discussion