さて、バースデーカードなんかで、開いたりボタンを押したりすると、音楽が鳴るのがありますよね? あれを、好きな曲で作りたいなって思いました。
こんなカード👇
とりあえず音楽を鳴らす仕掛けが出来たので、前編としてご紹介します。
- 楽譜データの変換ツールをMac対応にする
- Google App Scriptに移植しよう
- スプレッドシートを楽譜エディターにする
- 楽譜データを変換する
- ディストーションをかける
- 試奏してみる
- 後編へつづく
メロディを鳴らすガジェット(?)を作りたい場合、Arduinoのtone()関数を使う方法がありますが、Arduinoは大きくてカードに収まらないうえ、tone()は単音しか出せないので面白味がありません。
欲しい機能はこんな感じです。
- 小さいマイコンで動く
- 省電力
- 和音を鳴らせる
- 楽譜データが作りやすい
こういうのには大抵先人がいるもので、探してみると早速ぴったりのものが見つかりました。
弘前大学の小山先生が公開されている、mymelo2というプログラムです。
これが素晴らしい出来で、8ピンの小さなマイコンAttiny85(Digisparkでも!)で動かせて、3音までの和音を鳴らせるうえ、ボタンをつければ再生/停止を操作できて、再生後はちゃんと省電力モードに入ってくれます。
さらに、楽譜データを簡単に作れるインフラまで用意してくれていて、至れり尽くせりです。
というわけで、このプログラムを少し自分好みにカスタマイズして、使わせてもらおうと思います。
楽譜データの変換ツールをMac対応にする
さて、mymelo2では、ドレミ表記で書いた楽譜データを、付属の変換ツール(mymelo.wsf)でArduinoのヘッダーファイルに変換して使います。
ところが、変換ツールはWSHというWindows向けのスクリプトで作られているので、そのままではMacで利用することができません。 ja.wikipedia.org
うーん、Macでも動かしたい。
じつはこの変換スクリプト、中身がほぼJavaScriptなので、変換ロジックをWebアプリに移植すれば、マルチプラットフォーム対応に改造できそうです。
Google App Scriptに移植しよう
Webアプリと言いましたが、後の運用のために、Google App Script(GAS)へ移植することにしました。
GASもほぼJavaScriptなので、ほとんどそのままで動かせるはずです。
GASの使い方については、探せばすぐ出てくるので割愛しますが、使い始めはこの辺りが参考になると思います。
変換処理を抜き出す
まずはmymelo.wsfから、26行~364行あたりの変換処理を、ゴソッとコピーしてきます。
ついでに、45行からの4行は不要なので、削除しておきましょう。
var sh = new ActiveXObject("Shell.Application"); var ado = new ActiveXObject("ADODB.Stream"); var fso = new ActiveXObject("Scripting.FileSystemObject"); var mymelo = fso.GetFile(WScript.ScriptFullName).ParentFolder;
データの入出力部分を改造
入力部分
まず、コピーした処理をまるごと関数に入れて、曲名と入力文字列は引数で渡す形にしておきます。
function convert(song_name, input) { <上でコピーした処理> }
曲名を設定している行を探し、引数で受けたものを代入するように書き換えます。
// 変更前 var s = "// " + fso.getFileName(mmlfile) + "\n"; // 変更後 var s = "// " + song_name + "\n";
ファイル読み込み部分も、同じように探して書き換えます。
// 変更前 var S = readFile(mmlfile); // 変更後 var S = input;
出力部分
出力処理は、353行~362行辺りの減衰矩形波/正弦波の確認フォーム処理に組み込まれていますが、とりあえず正弦波の決め打ちにしつつ、出力先を返り値にしておきます。
s += "#define SINE_WAVE\n"; var output = s + SW + "0};\n" + gakufu + "0};\n"; console.log(output); return output;
ついでに長音符改行時の挙動を修正
こんなふうに、長音符の途中に改行が入ると、変換がうまくいかないという問題がありました。
ドーーーー ーーー
アウフタクトを多用する曲だと、小節単位で改行できなくて不便です。
入力文字列の整形のところに、行頭が長音符なら改行を削除する処理を追加すれば、このエラーを回避することができました。
.replace(/\n\s*[ー^]/g, "^") // 行頭にーor^があれば次行と合体
WSH特有の関数を置き換える
といっても、メッセージ表示部分だけなので簡単です。
WScript.Echo()
を、全部console.log()
に置き換えて、WScript.Quit()
を削除すればOKです。
スプレッドシートを楽譜エディターにする
さて、mymelo2では、テキストで手軽に楽譜データを作ることができますが、音符によって文字数が違うので、複雑なリズムを打ち込むのには少し不便です。
`ド`レ`ミ`レーシソ`ドーシラソーラシラ ーシ`ドソーファミファ+ーミファ+ソ+ーラシラ
そこで、Excelなどのスプレッドシートを使って、1セル1音で打ち込むという方法を考えました。
A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
`ド | `レ | `ミ | `レ | ー | シ | ソ | `ド | ー | シ | ラ | ソ | ー | ラ | シ | ラ |
ー | シ | `ド | ソ | ー | ファ | ミ | ファ+ | ー | ミ | ファ+ | ソ+ | ー | ラ | シ | ラ |
これなら、音の長さと見た目が一致するので、直感的にリズムを打ち込んでいくことができます。ピアノロールUIの縦軸を圧縮した感じですね。
具体的には、Googleスプレッドシートで楽譜を作り、GASでヘッダファイルに変換するというワークフローにします。
変換ツールをGASに移植しておいたのは、このためです。
スプレッドシートにすることで、小節ごとに罫線を付けたり色分けしたりもできるので、フレーズの編集が劇的に楽になります。
楽譜データを変換する
さて、ここからがGASの本領発揮、Googleスプレッドシートと、Googleドライブを組み合わせて、入出力を追加します。
あらかじめ、Googleドライブにmymeloのスケッチフォルダーをアップロードして、mymelo.hファイルのIDを取得しておきましょう。
アップロードしたmymelo.hファイルを右クリックし、「共有可能なリンクを取得」で表示されるURLの、「/file/d/」に続くランダムな文字列部分がIDです。
そうしたら、main()にスプレッドシートからの文字列読み込みと、ドライブへのファイル書き出し処理を追加します。
function main() { // アクティブなシートを取得 var sheet = SpreadsheetApp.getActiveSheet(); // データ範囲を取得 var range = sheet.getDataRange(); // 範囲内の値を取得 var values = range.getValues(); // 2次元配列が来るので、区切り文字なしで文字列に結合 var score = values.map(value => value.join('')).join('\n') // 変換処理、曲名はシート名から取る var output = convert(sheet.getSheetName(), score); // Googleドライブのmymelo.hに上書き保存 var file = DriveApp.getFileById('調べておいたmymelo.hのID'); file.setContent(output); }
あとは楽譜のシートを開いておいてから、main()を実行すれば、mymelo.hが更新されるはずです。
初回実行時のみ、「このアプリは確認されていません」というダイアログが表示されるので、「詳細」→「安全ではないページに移動」→「許可」で、実行権限を与えてあげてください。
と、ここまで書いておいてナンですが、書き出した後のステップは、まだうまい方法を模索中です。
Googleドライブ上のArduinoスケッチを、直接Arduino IDEで開けるといいんだけどなぁ、できないかなぁ。
とりあえず良い方法が見つかるまでは、でき上がったヘッダーファイルをダウンロードして使うことにしましょう。
ディストーションをかける
さて、でき上がったものを鳴らしてみると、正弦波ではちょっと音がマイルドすぎました。
かといって矩形波では少し安っぽい感があるので、ちょっと力技っぽいですが、Excelで波形を加工してディストーションをかけ、パンチのある音を目指します。
mymelo2の波形生成に使われている波形テーブルは、8bit×256ステップのなので、こんな感じで。
index | sin | result |
---|---|---|
0~256の連番 | =(SIN(RADIANS(([@index]/256*360)-90))+1) *128 |
=(MAX(variable[sat],MIN((256-variable[sat]),[@sin]))-variable[sat])*(256/(256-variable[sat]*2)) |
index列に用意した連番を元に、sin列に8bitの正弦波を作って整数領域に移動
別途variableテーブルを用意して、sat列に閾値を入れる
result列で、閾値ぶん上下をクリップ
できたテーブルは、カンマ区切りにしてココに入れます↓
// 正弦波(値:0~255, データ数:256) const char W[] PROGMEM= { この中身 }
何度か鳴らしながら閾値を調整して、結局少し鈍らせた矩形波という感じになりました。
選ぶスピーカーによっても、鳴り具合が違うと思うので、色々試してみようと思います。
試奏してみる
ということで、ひとまず環境が整ったので、何曲か書いてみました。Digisparkを使うと、簡単に書き換えて試せるので、編曲が捗ります。
Billie Eilish / Bad Guy
つづいてビリー・アイリッシュの「bad guy」やってみた、リズムが面白いのでピコピコサウンド映える。 pic.twitter.com/TtgYzPXoIT
— アツユキ (@aaa_tu) May 22, 2020
King Gnu / Sorrows
King Gnuの「Sorrows」、こんどは生のAttiny85に書き込んでみた。 pic.twitter.com/MQBSr8T1Ws
— アツユキ (@aaa_tu) May 25, 2020
Iron Man 3 / Can you dig it
アイアンマン3より「Can you dig it」
— アツユキ (@aaa_tu) May 27, 2020
楽譜データをスプレッドシートで書けるようにしたので、長めのフレーズも簡単に作れるようになった pic.twitter.com/8cOQT2nIEC
LiSA / 紅蓮華
ややアレンジのコツが掴めてきたので、最初に作った「紅蓮華」をちょっと改良した
— アツユキ (@aaa_tu) June 3, 2020
見た目に変化がなく地味なので、賑やかしにオシロを繋いでみた pic.twitter.com/gkZZP45T77
これは楽しい...!
後編へつづく
カードに仕立てるための材料待ちなので、続きは後編をおまちください。
今日はここまで!