読者です 読者をやめる 読者になる 読者になる

音の鳴るブログ

鳴らないこともある

テキストファイルを可聴化するコマンド mimi-grep を作った

% npm install -g mimi-grep

これで mimi-grep コマンドがインストールされる。

使い方は

% mimi-grep <filename>

と、するだけでデフォルトだとファイルの各文字の文字コードMIDIノート番号として高速に再生する。

-c オプションで作曲アルゴリズムを切り替えられる。

池田亮司っぽいのとか

% mimi-grep -c beep <filename>

ドローン。

% mimi-grep -c drone <filename>

他にはリズムマシンがある。

% mimi-grep -c drum <filename>

音を出す部分は node-speaker というライブラリを使っているのだけど、インストールに失敗するとか使いたくない場合は、

# mac の場合 SoX play コマンドでも再生できる
% mimi-grep --stdout <filename> | play -r 44100 -t s16 -c 2 -

とか

# linux の場合 ALSA aplay コマンドで再生できる
% mimi-grep --stdout <filename> | aplay -f cd

みたいに stdout 経由で音を出すこともできる。

音を出すアルゴリムは Web Audio API ( の node でも動くやつ ) で書いてあって簡単に追加できる。こんな感じ

中身はかなりいい加減で、もうちょっとちゃんと作ってリダイレクト経由で実行させたり、作曲アルゴリムやパーサーをプラグイン化して自由に追加したりできると便利そうなんだけど、ノウハウがない状態で適当にやると絶対に失敗しそう。

コマンドラインからウェブオーディオのコードをちょっと試す

先日作った、JavaScript 実装の Web Audio API を使って、コマンドラインからウェブオーディオのコードをちょっと試すやつを作った。

使い方は簡単で、グローバルインストールすると wae というコマンドが使えるようになる。

$ npm install -g wae-cli

で、適当にコードを書いて ( audioContextwae コマンドから自動的に与えられる AudioContext )

// coin.js
const osc = audioContext.createOscillator();
const amp = audioContext.createGain();

osc.type = "square";
osc.frequency.setValueAtTime(987.7666, 0);
osc.frequency.setValueAtTime(1318.5102, 0.075);
osc.start(0);
osc.stop(2);
osc.connect(amp);
osc.onended = () => {
  process.exit();
};

amp.gain.setValueAtTime(0.25, 0);
amp.gain.setValueAtTime(0.25, 0.075);
amp.gain.linearRampToValueAtTime(0, 2);
amp.connect(audioContext.destination);

実行すると音が鳴る。

$ wae coin

オプションを工夫するとWAV形式で出力したりできる。 ドキュメントに書くのを忘れたけど、この場合はスピーカーから音を出す必要がないので、5秒の音声でも0.何秒かで出力してくれる。 しかも setInterval などを使って逐次的に処理するようなコードを書いても上手に実行してくれる。

$ wae coin -o coin.wav

module.exports = function で書けば引数を渡したりもうちょっと高度なコードが書ける。

// beep.js
module.exports = (audioContext, frequency, duration) => {
  const osc = audioContext.createOscillator();
  const amp = audioContext.createGain();

  osc.frequency.value = frequency;
  osc.start(0);
  osc.stop(duration);
  osc.connect(amp);

  amp.gain.setValueAtTime(0.5, 0);
  amp.gain.linearRampToValueAtTime(0, duration);
  amp.connect(audioContext.destination);
};
$ wae beep -- 1760 0.5

ベースで使っている web-audio-engine というライブラリが完全ではない (例えば現状 ConvolverNode や DynamicsCompressor が未実装など) という問題があるけど、ちょっと試したい時にブラウザをわざわざ開かなくて良いので便利だと思う。

関連

JavaScript で Web Audio API を実装した

github.com

以前から Web Audio API に興味があって暇なときには仕様を読んだりしていたのですが、だいたい分かったぞ!!と思って勢いで書きました。すべて JavaScript で書いてあるのでブラウザはもちろん Node.js でも動作します。Node.js で動かす場合はレンダリング結果をストリームとして出力するかwav形式でエクスポートできます。

オンラインのデモ (web-audio-engine と native Web Audio API の比較ができます)

web-audio-engine :: demo

先行する事例の

と比較すると、 チャネルの動的適応 (入力のチャネル構成によって下流のチャネル構成が変化する) や AudioNode のライフサイクル (動作しないエッジを擬似的にばっさりと切断する) を実装していてより仕様に沿ったものとなっています。

まだまだ未対応なノードとかメソッドなどが残っていますが音を出す仕組みのあたりは一段落したという感じです。ちょっと疲れてきて作業をするたびにコードが意味不明になっていく状態になったので、しばらくはコードにコメントを足すぐらいにして、また気力と体力が復活したら少しずつ機能を足していこうかと思います。

実装したAPI

  • AudioBuffer
  • AudioBufferSourceNode
  • AudioContext
  • AudioDestinationNode
  • AudioNode
  • AudioParam
  • BiquadFilterNode (audio rate parameter is not supported)
  • ChannelMergerNode
  • ChannelSplitterNode
  • DelayNode (noisy..)
  • GainNode
  • OscillatorNode (use wave-table synthesis, not use periodic wave)
  • PeriodicWave
  • ScriptProcessorNode
  • StereoPannerNode
  • WaveShaperNode

未実装のAPI

  • AnalyserNode
  • AudioWorkerNode
  • ConvolverNode
  • DynamicsCompressorNode
  • IIRFilterNode
  • PannerNode
  • SpatialPannerNode

JavaScript でドラムタブを記述する

var _, o, x, X;

var hihat = X - o -   X - x *   X - o -   X * o--;
var snare = _ - - -   X - o -   - - - -   X - - o;
var basd  = X - X -   - - - -   X - X -   - - o--;

console.timeline(hihat, snare, bass);

お焚き上げ2015

年末なので今年書いた npm モジュールをまとめてみます。


OscMsg v0.3.0

OSC のメッセージを JSON にデコード/エンコードするライブラリ。去年からちょくちょく OSC を使って Node.js と openFrameworks や Max/MSP と連携する案件を手伝ったりしていたので非常に重宝した。似たようなライブラリに node-osc-min というのがあるのだけど、壊れたデータを渡したときに例外が出るのとかブラウザ対応がいまいち気に入らなかったので自分で作った。とはいえブラウザで使うことはないなーという印象。


WebAudioScheduler v1.0.0

Web Audio API を使うときに必読の この記事 をベースに作ったスケジューリングライブラリ。時間と関数とパラメータを登録しておくと良いタイミングで呼び出してくれる。Web Audio API を使うときはこれがないと何もできないというレベルで重宝した。名前に反して Node.js でも動くので、そちらでも大活躍。(Web Audio API で使うときは AudioContext#currentTime の時間を指定、そうでないときは Date.now() / 1000 の時間を指定できる)


ADSREnvelope v1.0.0

Web Audio API で ADSRエンベロープを作るのが意外と難しいので、それだけのために作った。ADSR の各パラメータを設定すれば、それに応じた AudioParam 向けのメソッドを生成してくれたり、x秒時点の値を計算してくれたりする。後者の機能は Node.js でも動くので、そちらでも大活躍。デモサイトではエンベロープを可視化したりできる。


Ciseaux v0.4.0

Web Audio API の AudioBuffer を切ったり貼ったり編集できるやつ。がーっと編集して最後に WebWorker でレンダリングするみたいな少し凝った構成になっていて、作って満足した感があった。wav の読み込み/書き出しのみなら Node.js でも動く。


InlineWorker v1.0.0

github.com

関数からWebWorkerを作るやつ。上のライブラリで使っている。Node.js でも動く。ここに書いたやつ。


SeqEmitter v1.2.0

簡単にシーケンサーを作るためのベースモジュール。楽譜情報のイテレーター (timeという要素を返すオブジェクトを返すやつ) を渡すと良いタイミングでイベントとして発火してくれる。


IntervalIterator v1.0.0

上のモジュールで使っているやつ。time という要素を持つオブジェクトを返すイテレーターをラップして、1秒単位とかでまとめて返してくれるイテレータ


MIDIKeyboard v0.2.1

MIDI キーボードの演奏情報をイベントエミッターの API で受信できるやつ。Web MIDI API と Node.js で使える。


LaunchControl v0.4.3

Novation LaunchControl の捜査情報をイベントエミッターの API で受信できるやつ。Web MIDI API と Node.js で使える。


MIDIDevice v0.4.1

上記の2つのベースになっているモジュール。Web MIDI API と node-midi の差を吸収するみたいなやつ。ここに書いたように親クラスを切り替えて継承して使う。


他にもあったと思うけど忘れた。という感じ。

だいぶ前に作ったライブラリが未だに人気があるので、来年はこれをやり直そうかなと思っていて、さいこうの仕様を考えながら年越しをしたいと思います。

Google Chrome の右上の名前をだるくなくした

Google Chrome の右上に本名が表示され続けてだるい。前は簡単に消せたけど今回のは黒い画面で何か入力しないといけないとか意味不明で困っていたのだけど、名前のところをクリックすると編集可能っぽいので、できるだけだるくない名前にした。

f:id:mohayonao:20150729061252p:plain

f:id:mohayonao:20150729061302p:plain

f:id:mohayonao:20150729061317p:plain

f:id:mohayonao:20150729061847p:plain

f:id:mohayonao:20150729061852p:plain

Web Music ハッカソン で Tシャツ をもらいました

Web Music ハッカソン で WebSocket で演奏情報を分散配信して複数のブラウザでひとつの音楽を演奏するシーケンサを作って、頑張った賞みたいなので LittleBits のTシャツをもらいました。

コンセプト的なやつ

f:id:mohayonao:20150726201422p:plain

  • サーバーがある
  • サーバーは音楽の演奏情報を持っている
  • MIDIコントローラー等でサーバーの演奏情報を操作できる
  • たくさんのクライアントがある (10-50台くらいを想定), WebSocket で接続
  • それぞれのクライアントにバラバラに演奏情報 (JSON) を送信する
  • 空間全体でひとつの音楽になる

経緯

去年からちょくちょくウェブオーディオを使ったインスタレーションとかライブを手伝っているのですが、そこで得られたノウハウが全然形として残っていなかったので整理したかったのと、あと今後のために試しておきたかったこととか React とか flux とかの最新のトレンドとかを全部ぶっこんでみたかった。

当日のハック

諸事情あってかなりの張り切りモードになっていたせいで事前に準備しすぎて、あとは細かい調整するくらいしかできない状態だったのだけど、当日一緒になった方々に機能を追加してもらえたりハッカソンぽい感じで作業できた。僕は最強JSビルド環境厨みたいなところがあって、何も考えずに Node.js で ES6 で React で Flux (しかも自分で実装したやつ) で npm run scripts を使っていてかなり制限のきつい状況だったのだけど、うまい具合に対応してもらえてよかった。

スマートフォンの向きでシンセリードのフィルターのかかり具合を制御できる機能を追加してくれた

1x1 の Canvas がチカチカするだけだった画面に 波形 と スペクトラム を表示してくれた

ありがとうございました!

デモ

会場のWiFiが想定外に悪くて全然できなかった。どこか10台以上のクライアントを使ってデモさせてくれるところないですかね?

一台のPCで9つのブラウザウインドウを開いて実行している画面。違う音が出ているので画面の表示はバラバラ、同時に聞くとひとつの音楽になる。本来はこれをハッカソン参加者のそれぞれのPCで実行するつもりだった。

f:id:mohayonao:20150727102503p:plain

一応サーバーがなくても動くスタンドアロン版も用意しているので、雰囲気をつかむだけなら試せる。こっちはめっちゃ React ってる。演奏情報のメッセージングをサーバーを介するかクライアント単体で完結させるかだけなのでベースのコードはほとんど共有できている。

http://mohayonao.github.io/web-music-hackathon-04/

f:id:mohayonao:20150727103701p:plain

懇親会

  • @sascacci さんと楽器の手触り感の気持ちよさの話
  • @aike1000 さんと開発環境とかテストの話
  • @g200kg さんのGPUを使った信号処理の話

あと、今度 YAMAHA から発売される reface はスピーカーがついてて良いみたいなこととか DX7II の思い出みたいなことを話していた気がする。