音の鳴るエディタことVim

音の鳴るエディタ - ✘╹◡╹✘の技術的解説。

おさらい

音の鳴るエディタ

眼を閉じた状態で"Hello"と入力して、画面を見ずに正しく"Hello"と入力されていることを確認したい。
そこで、キーを叩く度にそれぞれ固有の音が鳴るようにした。
プログラミングしながら演奏できる。
開発者集めてジャムセッションとかできると思う。
人月の神話っぽくならないように注意したい。

仕組み

Vimはキーイベントが取れるので、キーを押したときにカーソルの下にある文字を取得して、それを非同期でRubyのプログラムに渡す。objective-c調べて書くの面倒だからRuby使った。Rubyの方は、文字列の文字コードと見て適当に半音階ずつの周波数を決める。a, b, c, d, ...と半音ずつ上がっていく。キーイベントでキーが取得できて非同期でシステムコマンド呼び出せるエディタだったら何でも使えると思うけど、5分ぐらい探した限りVimぐらいしかなかった。非同期にするのにvim-proc使ってるけど、いま使ってるMacbookAirだと1秒に3〜4文字ぐらいのタイプ速度なら支障ないけど、環境によって遅くなったりするっぽい。

.vimrc

autocmd CursorMovedI * :call vimproc#system_bg($HOME . "/bin/vim-key-sound.rb '" . getline('.')[col('.') - 2] . "'")

~/bin/vim-key-sound.rb

#!/usr/bin/env ruby

require "coreaudio"

class SinWaveSounder
  LONG = 44000

  scale = 2.0 ** (1 / 12.0)
  FREQUENCIES = 28.times.map do |i|
    220 * (scale ** i)
  end

  def initialize
    dev = CoreAudio.default_output_device
    @buf = dev.output_loop(LONG)
  end

  def sound(frequency, sec)
    phase = Math::PI * 2.0 * frequency / LONG
    LONG.times do |i|
      @buf[i] = ((0.4 * Math.sin(phase*i)) * 0x7FFF).round
    end

    @buf.start
    sleep(sec)
    @buf.stop
  end

  def random_sound(seed, sec)
    i = seed.ord % FREQUENCIES.size
    sound(FREQUENCIES[i], sec)
  end
end

sounder = SinWaveSounder.new
sounder.random_sound(ARGV[0], 0.1)

音質

エディタから音が鳴るようになったら当然7.1chで聴きたいと思うだろうし、併せてこちらもお読みください。

7.1ch - ✘╹◡╹✘
http://r7kamura.hatenablog.com/entry/2012/08/10/135239