サイン波を発振しよう

今日みたいな、こんな日はお洒落にサイン波を
発信したくなりませんか?


以下、URLのC言語Rubyでトレースしてみました。
(少々変更してます)


まずは音を出してみよう
http://homepage3.nifty.com/rio_i/lab/oss/002sound.htm


実行結果としては、
Hello, worldよろしく、440Hzのサイン波を再生するんですが
コードの内容は簡単で以下の事をしています。

  1. サウンドバイスの設定
  2. サイン波生成(440Hz)
  3. サイン波をサウンドバイスへwrite


ここまでできたら、サイン波をノコギリ波や矩形波にしてみたりして遊べますな。
そうそう、サイン波っていうのはポーという音です。ポー。

require 'soundcard.rb'
include SoundCard

sec   = 1     #1sec
freq  = 440   #440Hz
fs    = 44100 #44100
gain  = 32767 #16bit


class Array
  def playable
    self.collect { |d|
      raise if d > 32767 || d < -32768
      d = 65536 + d if d < 0
      [ d & 0xff , d >> 8 ]
    }.flatten!.collect { |d|
      [d].pack('c')
    }.join
  end
end

class IO
  def w_ctl(arg,data)
    self.ioctl( arg,[data].pack('V') )
  end
  def r_ctl(arg)
    ret = ''
    self.ioctl(arg,ret)
    ret.unpack('V')
  end
end

buf = Array.new(fs*sec) { |t|
  (gain * Math.sin(Math::PI* 2 * freq / fs * t) + 0.5).to_i
}
# plot buf[0..100] # if you want 

open('/dev/dsp','w') { |fd|

  fd.w_ctl( Param[:SOUND_PCM_SETFMT] , Param[:AFMT_S16_LE] )
  puts "fmts = #{ fd.r_ctl( Param[:SOUND_PCM_GETFMTS] ) } "

  fd.w_ctl( Param[:SOUND_PCM_WRITE_CHANNELS],1)
  puts "channels = #{ fd.r_ctl( Param[:SOUND_PCM_READ_CHANNELS]) } "

  fd.w_ctl( Param[:SOUND_PCM_WRITE_RATE],fs)
  puts "rate = #{ fd.r_ctl( Param[:SOUND_PCM_READ_RATE]) } "

  fd.write( buf.playable )
}

上記ファイルでのSoundCard.rbは以前、生成したファイルです。
以下のようになっています。

module SoundCard
  Param = {
    :SOUND_PCM_READ_RATE => 0x80045002,
    :SOUND_PCM_READ_CHANNELS => 0x80045006,
    :SOUND_PCM_READ_BITS => 0x80045005,
    :SNDCTL_DSP_GETBLKSIZE => 0xc0045004,
    :SNDCTL_DSP_SETFRAGMENT => 0xc004500a,
    :SOUND_PCM_GETFMTS => 0x8004500b,
    :AFMT_MU_LAW => 0x1,
    :AFMT_A_LAW => 0x2,
    :AFMT_U8 => 0x8,
    :AFMT_S8 => 0x40,
    :AFMT_S16_LE => 0x10,
    :AFMT_S16_BE => 0x20,
    :AFMT_U16_LE => 0x80,
    :AFMT_U16_BE => 0x100,
    :SOUND_PCM_SETFMT => 0xc0045005,
    :SOUND_PCM_WRITE_CHANNELS => 0xc0045006,
    :SOUND_PCM_WRITE_RATE => 0xc0045002,
  }
end


参考URL:
RubyからCのヘッダ定義を読み込みたい - きみのハートを8ビットキャスト