見出し画像

8ビットレトロゲームサウンドをAI作曲?する「8bit BGM Generator」を作った

はじめに

各所で脅威的なAIサービスが爆誕する今日このごろですが、「自作ゲームのBGMをAIツールでまかなえないか?」と考える人もけっこういるんじゃないかなと思います。

調べてみるとAI作曲ツールはたしかにいくつか見つかるのですが、たとえば私の場合、Pyxelというレトロゲームエンジンを愛用してまして、PyxelにはPyxelの独自形式があるので、wavやmp3ファイルで出力されても使えなかったりします。
(ほかにもTwiltterの相互フォローでPico8を使っている方が同じようなことを言っていました。)

あとは、magentaというAI作曲の有名なライブラリがあります。
これに好みのゲーム音楽を学習させてMIDI形式で出力させたりすることはできるっちゃできます。
が、そもそも環境を作ったり、データの準備をしたり、思い通りの曲が生成できるように調整したり、というのは現段階(2023/5)ではハードルが高い印象です。
まあ、magentaは即戦力的な実用性より使用者の学習用途という意義も大きいのだと思います。

そこで、Pyxelユーザー向けというややニッチなターゲットにはなりますが、だったらいっそ自分で作ってみようと思い立ちました。

Webアプリの紹介

以下のURLから実際にお試しいただけます。
Pyxelユーザー向け、と先ほど書きましたが、Pyxelユーザーでなくても使えます。

https://retro-bgm-generator.web.app/

GitHubのリポジトリはこちら。ReadMeが入っているので、詳しくはそちらをご覧ください。

YouTubeに簡単な紹介動画もアップしています。

自動作曲の基本方針

さて、この記事の目的はアプリの紹介・宣伝ではなく、テーマとして興味を持っていただけた方に技術的な情報共有をすることにあります。

といっても、あらかじめお断りしておくと、全般的に大したことはやっていません
もちろんこのnote記事のタイトルに「AI」とつけたのも流行りに便乗しているだけです。笑

ただ、個人制作で小粒ながらも自動作曲ソフトを開発して、かつそのノウハウを詳細に共有しているドキュメントはレアだと思うので、もし同種のことを考える方の目に触れて少しでも参考になれば、と思ってこの記事を書くことにしました。

発音数は3音だけ

まず、生成する曲の基本仕様(骨格)を考えていきます。

前提(制約)事項として、Pyxelのサウンドはファミコンやゲームボーイと似ていて最大4音発音(効果音も含めて)です。
さらに、ゲームにおいては効果音の再生が不可欠であることを考えると、問題なく使えるのは3音までです。
(4音使って、うち1チャンネルは効果音を鳴らすときだけ切り替えるというワザもあります。)

3音というのは大変少なく、ピアノで左手でド・ミ・ソと抑えれば終わりです。
ギターならコードの1つすら弾けやしません。
この中にメロディ・ハーモニー・ベース・リズムといった各要素を詰め込んでいく必要があります。

しかしながら、制作側にとってはこれはメリットです。
「3音しか使えないからね」って堂々と言い訳できますので。
それに、聴いているほうも「そうそう、8bitサウンドってのは3音とか4音の制約の中で頑張るんだよなあ」と思ってくれる(あるいはそう明確に把握していなくても、これまで聴いたことがある層なら感覚的に理解している)ので、音数が少ないことはマイナスにならないんですよね。

編成は「メロディ+ベース+ドラム」

8Bitサウンドで3音しか使えない場合の王道編成は、①メロディ+②サブメロディ+③ベース、です(※)。

メロディとベースは大抵の音楽ジャンルにとっては外せない存在なので、あともう1音(②)でメロディー(場合によってベース)とのハーモニーを作ったり、アルペジオやらリフっぽいフレーズを奏でたりして曲のコード感やノリを支えます。
そのため「ファミコンっぽいサウンド」を作ろうとすると、アレンジ面ではこの②がかなり重要です。

なんですが、8bit BGM Generatorではこの②を捨てて、①メロディ+②ベース+③ドラム(ノイズドラム)にしました。
理由は単純で、そのほうが作るのが簡単だから、です。

仮に①メロディ+②サブメロディ+③ベースの編成にする場合、たとえば音高の重なりを気にする必要があります。(ノイズ除いて)3音しかない8bit系な楽曲において、その3音の音高が重なるのはかなりもったいないです。
メロディとベースは、使用音域をばっさり切り分けてしまえば(たとえばベースがD2まで、メロディはE2から、というように)簡単に重なりを回避できますが、サブメロディパートも使用音域のレベルで分離しようとすると、ベースが低すぎたりメロディが高すぎたり、もしくは使用できる音域が狭くなりすぎたり、と苦しいことになります。
なので、重なりを避けながら音符を生成していくような実装が必要となり、まあできないことはないのですが、生成アルゴリズムをややこしくする要因になります。

またそれ以上に、「サブメロディ」と「ノイズドラム」を比較すると、後者は簡単にパターン化できるのに対して、サブメロディは前述のようにメロディのハモだったり、あるいは独立したアルペジオやリフだったりしてバリエーションが相当に豊富です。
だからこそアレンジのミソとなるんですが、自動生成する上では障壁になりすぎるので捨てました

(※)ちなみにファミコン等でも、4チャンネルめがノイズ波専用のチャンネルなので、4音目としてノイズドラムパートを入れることが多いです。
ただ曲調によってはノイズドラムは必ずしも必要ないので、より重要な3音としては「①メロディ+②サブメロディ+③ベース」だと思います。

曲の長さは8小節固定(短めループ)

次に「曲の長さ」について考えます。
BGM=ループ曲なので、何小節を1ループにするか?ということですね。

ファミコンをはじめとした8ビット時代のゲームミュージックの長さは、というと、初期の作品は2〜4小節くらいのかなり短いループの曲も多かったようです。

中期以降となるとそれが8小節や16小節、ものによってはもっと長かったりして、1曲の中で複数の展開がある曲も珍しくないです。

8bit BGM Generatorでは、編成の話同様「小さい方が都合がよい」ので、最初は4小節ループにすることを考えていたのですが、実際に試作してゲームのBGMとして流してみると、4小節ループはかなり短く感じました

メロディが上質だったらそうでもないかもしれないですが、残念ながらそこまでとは言えず、クセがやや強いので、4小節単位で繰り返されるとなおさらくどい印象になったのかもしれません。

反対に16小節以上にすると、今度は前半と後半でアレンジのパターンの変化が欲しくなってきたりして、(制作目線で)だいぶ手強くなってきます。
(後述しますが、現在の8bit BGM Generatorのベースやドラムは単一の演奏パターンを繰り返すだけです。)

なので、8小節が短すぎず・長すぎずのラインかなと結論しました。

ここら辺まででだいたいわかっていただけると思いますが、仕様を決めるにあたっては「最低限のクオリティは整えつつ、できるだけ手抜きする(仕様をを割り切る)」を重視しています。
でないと、私のようにスキルも根性も大したことない個人にはとても作り切れないので・・。

音の長さは16分音符単位

小節数を決めたので、次は1小節内の構成ですが、ここはあまり迷いなく、「16分音符単位」にしました。

8分音符が最小単位だと、曲調によっては物足りなくなりますし(全体的に音楽性よりノリでごまかす方向なのでなおさら)、32分音符は、曲調やテンポによっては効果的ですが、そこまでマストではないかなと。

もちろん16分音符単位にするということは、3連符をはじめとする2の倍数以外の音符が使えないことも意味します。
自分で作曲するのであれば、「3連符が使えない」という制約があるとやや寂しく感じますが、どうせ自動生成でカバーしようとしても活かしきれなくなるのがオチですし、あまり重視しなくてよいと判断しました。

コード進行はパターンから選ばせる

曲の編成・長さや細かさといった外枠的な設計以外に、「コード進行をどう決める?」という重要な論点があります。
具体的には「自動生成する」or「あらかじめよく使いそうなコード進行を登録しておいて選ばせる」の2択です。

前者は「うまく機能を作れれば爆発的なバリエーションを産める」というメリットがあります。

後者のメリットはここでも「簡単に作れる」です。
あとは、センスのよいチョイスができれば、自動生成よりも確実に、いい感じのコード進行の曲を生成できるという点でしょうか。

コード進行の自動生成は、今日ではそれほど珍しい機能ではありませんが(たとえば、よく使われるDAWのCubaseにもコードアシスタントという機能がついている)、個人開発する機能としてはまあまあ重たいです。

一方で、「定番のコード進行」というテーマはこれまで多くの方によって分析結果が整理されているので、わりと容易に情報収集できます。

なので、とりあえずはあまり欲を出さずに、「あらかじめよく使いそうなコード進行を登録しておいて選ばせる」の方針にしました。

次の悩みポイントは「どれくらいのパターン数を登録するか」です。
あまり多いと選ぶのが嫌になったりする人もいるので(これは個人差がかなりあると思いますが、私は過去にDTMやってて、ありとあらゆる選択肢が多すぎて何がベストか吟味しきれないのがすごく嫌でした)、かなり少ないですが8パターンとしました。

ただ、コード進行はやはり曲作りの中でもかなり重要なポイントなので、いくらなんでも8パターンの中からしか選べないというのは制限がキツすぎるかもしれません(Twitterでもそういう意見がありました)。
ここは将来的にはもうひと工夫したいところです。

チャンネル別の方針①:ドラム

次に各チャンネルの譜面の生成方法を考えていきます。まず一番簡単なドラムから。

ドラムはパターン化が簡単

ドラムには音程がなかったり、心地よい強弱のリズムがある程度パターン化されていたりするので、典型的なパターンを登録して、その中で選べるようにするだけで十分と考えました。

このような「あらかじめ設定されたパターンからドラムの演奏を選んで曲に埋め込む」という手法は、DTMではよく使われています。
市販のドラム音源などにはリアルな演奏の強弱まで含めた演奏パターンが付属されていたりしますし、Macでよく使われるLogic ProというDAWでは「Drummer」というドラムパート自動生成機能がついていて、自分で打ち込んだベースとノリを合わせてくれたりもします。

8bit BGM generatorではもちろん、そこまで凝ったことはできないので、シンプルにあらかじめ決められた8パターンの中から選ぶ形にしました。

ノイズドラムの音色

8bitサウンドのノイズドラムの場合、リアルなドラムのように「バスドラム」「オープンハイハット」「シンバル」といった各音色を細かく出し分けて聴かせる演奏をするというより、ノリを作る役割に専念することが多いように思います。
(そもそもシンバルの再現とかはかなり難しいです。)

ですので、8bit BGM generatorでも、基本的に登場させる音色は「バスドラム」(低くて強い)「スネアドラム」(高めで強い)「ハイハット」(高くて弱い)だけにしました。

あと、ドラム演奏ではフィルインのときにタムを回すことがよくあります。
タム回しは8bitサウンドでも三角波を利用して再現することが可能で、たとえばロックマンの曲などでは効果的に使われています。

8bit BGM generatorでもオマケ程度に、一部のドラムパターンのフィルイン(フィルインは4小節目と8小節目の終わりに固定で入るようにしています)にタムを組み込みんでみました。
まあこれは、こんなこともできるんだぜ、ドヤ?みたいな自己満足の色合いが強いです。笑

データの具体例

以下は実際に組み込んでいる演奏パターンのデータ例です。
1つのデータが16分音符で、:1がバスドラム、:2がスネア、:3がハイハット、0は休符。
「ドッツツ、パッツツ、ドッツツ、パッツツ」みたいな演奏ですね(雑表現)。

[":1", 0, ":3", ":3", ":2", 0, ":3", ":3", ":1", 0, ":3", ":3", ":2", 0, ":3", ":3"]

例外:ドラムレスの場合(擬似リバーブ)

編成を「メロディ+ベース+ドラム」にしたと言っても、ドラムが要らない曲も多々あります。
そのためドラムレスも選択できるようにしたのですが、「外したらメロディ+ベースの2音になる」というのもいささか寂しい感じがします。

そこで、せめてものちょっとした工夫として、ドラムレスの場合はメロディに擬似リバーブ(ディレイというほうが適切かも)をかけることにしました。
やっていることは単純で、「メロディを16分音符分遅らせて小さい音でリピートする」だけです。

ちなみにファミコン曲でも、こういったディレイを使った曲がたまにあります。
デチューン(音高を微妙にずらす)をかけたりするといい感じに響くのですが(FF3の「果てしなき大地」とかとても美しいです)、Pyxel音源だとデチューンがかけられないので、おまけ程度の効果になっています。

チャンネル別の方針②:ベース

次にベースです。
リズム感とコード感の両方を担うのでかなり大事です。

パターン化+コードと音域の考慮

ベースも基本的な方針はドラムと同じで、パターンを登録してユーザーに選んでもらう形としました。

ベースのパターンのバリエーションはドラムより多岐にわたりますが、8ビットゲームサウンドというジャンルに絞ると、よく使われるパターンはある程度思い当たりますので、やはり8パターンを決めて設定しました。

また、ドラムとの違いとして、ベースの場合は音程がある楽器なので、コードに応じた音を出す必要があります。
そのため、パターンとしては「ルート音」「ルート音の5度上」「ルート音の1オクターブ上」といった意味を指す情報を登録しておき、コードに応じて実際の音を決めていく必要があります。

さらに、編成考察のくだりでも少し触れましたが、メロディのチャンネルと音域が重ならないようする必要があります。

具体的には、あらかじめベースが使える最高音を決めておいて(D2固定にしています。三角派がいい感じにベースっぽく鳴る音域はある程度決まっているため、ここは動かせるようにはしていません)、「ルートの1オクターブ上」がD2を超えないように調整しています。

データの具体例

これらを踏まえて、以下が実際に組み込んでいる演奏パターンのデータ例です。

「12」はルート音、「19」はその7半音上=5度の音。「24」はオクターブ上(8度)の音。
この音にコードの「ルート音との音程差」「トランスポーズ」を加算して、最高音(D2=26)を超えないように調整します。

また「-1」は休符、「null」は何も演奏しない=前の音を維持する、を意味しており、例2は「8分音符のルート → 16分音符の1オクターブ上 → 16分音符の休符」を表します。

例1:[12, -1, 19, 24, 12, -1, 19, 24, 12, -1, 19, 24, 12, -1, 19, 24]
例2:[12, null, 24, -1, 12, null, 24, -1, 12, null, 24, -1, 12, null, 24, -1]

ちなみに、3度の音をベースに使おうとすると、コードがメジャーなのかマイナーなのかによって3度の音の音程が変わってきてしまいますが、8bit BGM generatorではシンプルなパターンしか登録していないので、使う音は1度・5度・8度に絞っており、その考慮は不要となっています。
(割り切りによるちょっとした恩恵。)

チャンネル別の方針③:メロディ

最後にメロディです。
ドラム・ベースと違い、パターンで済ませるわけにはいかないパートです。

コード感の補完がマスト

ここまでの方針から、

  • ベースでは1度・5度の音しか使わない

  • サブメロディのチャンネルはない

ので、コードの性格を決める3度の音や7度の音をメロディがカバーすることがほぼマストです。

また、ベースが必ずコードのルート音から始まるので(8bit BGM generatorの登録パターンでは少なくともそう)、各コードの音の始まりはルート音を避けたほうがベターです。
コードCに対して、ベースがC、メロディーもC、他に音程感のあるパートなし、となるとコードの性格がわからない演奏になってしまうためです。

これらを踏まえて、8bit BGM generatorのメロディ音生成では以下のルールを設けました。

  • 各コードの最初の音はルート音を避ける

  • メロディの生成をした後にチェックして、コードの性格を決める重要な音(3度・7度など)が全て入っていなければやり直す

「コードの性格を決める重要な音」のチェックに1度(ルート)や5度を入れていないのは、ベースでカバーされる(5度はされないこともあるが、ルートと3度からだいたい推測できる)ためです。
「1度・3度・5度・7度の音が全て入っている」を必要条件としてしまうとかなり制約が大きいですし、人間が普通に作るメロディとも乖離が大きくなってしまうので。

ランダムに音を配置していく

上記のルールを守った上で、あとは調性とコードに適合する音(※)を先頭から順番に配置していきます。
音符の配置アルゴリズムの概略は以下のとおりで、上から順に判定します。

  1. 音符の長さを決める。音符の長さはパラメータに応じて、「4分音符」「8分音符」「16分音符」から選択する。

  2. 所定の確率<パラメータ>で、休符を置く。ただし休符の次は音符が必ず2個以上置かれるものとする。(実際の曲はそうとも限らないが、休符が挟まれすぎると不自然に聞こえたり、サブメロディがない分あまり空白を作らないようにしているため。)

  3. 直前の音が休符か、現在の調性とコードで使える音から外れた場合は、コード構成音からランダムで次の音を選ぶ。たとえばCならド・ミ・ソから選ぶ。

  4. 所定の確率<パラメータ>で、前の音を伸ばす。

  5. 次の4つの中から配置パターンを選択する。「①前の音を連続させる」「②トリル(ド→レ→ドやド→シ→ドのように、1回だけ隣の音に移ってまた戻ってくることをここではトリルと呼んでいます)」「③他のコード構成音との間を階段状に演奏する(たとえばコードがFで前の音がドのとき、ド→レ→ミ→ファ など)」「④任意のコード音(3と同じ)」

(※)基本的にはCメジャー(トランスポーズなし)なら「ドレミファソラシド」が使える音。ただ、ノンダイアトニックコード(Cメジャーに対してA♭など)の場合は、「ラ♭シ♭ドレミ♭ファソラ♭」などスケールから外れた音を指定することもある。

多少書ききれていない条件分岐や例外もありますが、基本的にはこれだけのルールです。

言うまでもなく、こんなのでは多少作曲ができる人が作るメロディの足元にも及びません。

ただ、何度も触れているようにに、100点満点どころか「なんとかそれっぽく聴こえればOK」くらいのレベルを目指しているので、明らかに不快・不自然なメロディになっていなければ大丈夫(ベース・ドラムと力を合わせればなんとかなる)っしょ、という考えです。

まとめ

かなり長文になってしましたが、さわりの部分でも書いたように、1つずつ分解していくとどれも大したことはやっていません。

ただ、「8ビット風レトロゲームサウンド」というジャンルに特化しているためか、少ない労力の割にはまともな出来栄えになったと思います。

Twtterの反響も意外と良くて(当人比。ちなみに私はフォロワー200人程度の弱小アカウントです)嬉しかったです。

今後改善したいこと

  1. メロディラインをより人間らしくする。現状だと「不愉快ではない程度」のレベルなので、「うっかりするとアマチュアが作ったメロディと錯覚する程度」まで昇華したいです。アイデアはすでにあるんですが、適用して実際にどうなるかは未知数。

  2. MIDIファイル/MMLファイルなど、Pyxel以外のユーザーに生成した曲を使ってもらいやすいようにするためのファイル出力機能。(Twitterの反応からするとニーズありそう。)

  3. 4音化対応、すなわちサブメロディパートの追加。2に書いたとおりPyxel外で使うなら3音にこだわる意味もないですし、Pyxelにしても4音+割り込みSEは少し工夫すれば可能です。

  4. 上級者向けに、コードやドラムパターンを自由編集できる機能。

このあたりに挑戦していきたいと思います。
(2023/10/11追記:最新版ver1.20にて、1〜3まで対応済みです。)

この記事が気に入ったらサポートをしてみませんか?