波形botなるものを作りました

2014/01/24初稿
2014/01/26ソースコード追加
2014/01/28ソースコード更新
2014/05/26ソースコード更新
2014/05/28スペクトログラム追加
2014/06/01波形/スペクトログラムの算出方法を変更

 波形bot@waveform_botなるものを作りました。みんなフォローしてね!
 正直趣旨はこれで終わりなんですが、それだけで終わるのもあれなので、波形botの概要等々を説明します。

・波形botの概要
 1時間に1回、自分が持っているランダムに抽出されたある1曲についての曲情報を、波形,RMS値,スペクトログラムの画像とともにつぶやく

・曲情報の概要
 ライブラリを”おおむね” /アーティスト名/アルバム名/曲名.wavで作っているので、そこからアーティスト名、アルバム名、曲名及びwaveフォーマットをアーティスト名:xx,アルバム名:xx,曲名:xx,ビット深度/サンプリングレートの順で表記
 ※あくまで”おおむね”なので例外の場合もあり、曲名やアルバム名が抜けたりする
 ※アルバム名をつぶやくと140字の制限に引っかかることが多いので、つぶやきにはアルバム名を含めていない。画像ファイルには載せてある。

・画像ファイルの概要-波形

 ・画像ファイルには曲情報をタイトルとし、波形(赤と青)、RMS値(黒線)をグラフにして表している。
 ・赤がLch、青がRch(普通はbLueで青がLch、Redで赤がRchのことが多いので注意)
 ・波形とRMS値は縦軸に大きさ、横軸に時間を取って表示している
 ・波形の音量の大きさはリニア表示
 ・RMS値の大きさはdB表示
 ・RMS値はおおよそ30msで平均を取っている

例1(ある曲をWavelab7で表示した波形)


例2(ある曲を波形botで表示した波形)


例3(1kHz,-96dbから0dbのサインスイープをWavelab7で表示した波形)



例4(1kHz,-96dbから0dbのサインスイープを波形botで表示した波形)
(短いサインスイープなので、分割したところで切れ目が出来ている)


・画像ファイルの概要-スペクトログラム

 ・X軸が時間、Y軸が対数表示の周波数を表示したスペクトログラム
 ・周波数のレベルによって黒からオレンジへと変異する
 ・サンプルデータは単純なLR合成値(そのため、LRで位相が反転していると、スペクトログラムには反映されない)
 ・FFTのサンプル数は16384(そのため、最低域の描画はあてにならない)
 ・FFTは4096サンプル毎に実行
 ・7項ブラックマンハリス窓を採用
 ・サンプリングレートによってY軸の目盛りが変化するため、注意。下から大目盛りが10,100,1000,10000(Hz)を表す。

例1(44.1kHzの場合の1kHz)

例2(88.2kHzの場合の1kHz)

例3(44.1kHzの場合の20kHzから20Hzのサインスイープ)
(短いサインスイープなので、分割したところで切れ目が出来ている。以下同様)

例4(88.2kHzの場合の、20kHzから20Hzのサインスイープ)

例5(88.2kHzの場合の、44.1kHzから20Hzのサインスイープ)

ソースコードの説明
 Windows環境のruby 2.0.0で書いています。スパゲティおいしいので読みづらいですが、分からない部分をコメント等して頂ければ、補足説明します。
#処理に必要なライブラリの読み込み
require "fileutils"
require "rubygems"
require 'twitter'
require 'rmagick'

$hz=0
$bit_per_sample = 0

#data:String,byte:Int
#バイナリ形式で受け取ったデータを、bit深度に応じて数値変換し、配列で返す
def readInt(data, byte)
 binary_data = Array.new
 binary = Array.new
 num_data = Array.new

 if byte == 2 #byte=2は16bitなので、rubyのunpackが使える
  num_data = data.unpack("s*")
 end
 if byte == 3 #byte=3は24bit。rubyのunpackに24bitオプションが無いので、定義する
  binary_data = data.unpack("C*") #まず8bit区切りunsigned数値配列として読み取り
  binary_data = binary_data.each_slice(3).to_a #8bit区切りのものを24bit区切りにするために、3つずつ要素を区切る
  puts "いえい1"#いえい・。・v 時間かかる処理なので、進行を標準出力で確認
  binary_data.each{|binary|
   num = (binary[2] << 16) + (binary[1] << 8) + binary[0] #8bitが3つなので、シフトして24bitデータに
   num = -*1

follow_list = Array.new
ngfollowers = Array.new
ng = 0

open("ngtwitter.dat") {|file|
 while l = file.gets
  ngfollowers.push(l.chomp)
 end
}

follower_ids =
client.follower_ids("waveform_bot").each do |id|
 ngfollowers.each{|fid|
  if fid.to_i == id.to_i
   ng = 1
  end
}
 if ng == 0
  follower_ids.push(id)
 end
 ng = 0
end

friend_ids =

client.friend_ids("waveform_bot").each do |id|
 friend_ids.push(id)
end
follow_list = (follower_ids - friend_ids)

nglist = open("ngtwitter.dat", "a")
follow_list.each{|id|
 #いったんフォローでエラーが起きたユーザーは、次回からフォローリクエストしない
 begin
  client.follow(id)
  nglist.puts(id)
 rescue
  nglist.puts(id)
 end
}
nglist.close

---
threadspectrum.rb
---
require './fft_lib.rb'
#ここのプログラムを使用いたしました
require './fft_lib.rb'

#filepath:分割したファイルのパス
#number:何スレッド目か
#threadsize:分割した際の配列サイズ
#bit:bit深度による上限値の絶対値
#frame:FFT時のサンプル数
#buffer:FFTのサンプルとサンプルの間のサンプル数
#hz:サンプリングレート
def spectrum_pararell(filepath,number,threadsize,bit,frame,buffer,hz)
 
 number = number.to_i
 threadsize = threadsize.to_i
 bit = bit.to_i
 frame = frame.to_i
 buffer = buffer.to_i
 hz = hz.to_f
 
 wav = open(filepath).read
 wavs = wav.split("\n")
 threadsize = (number - 1)*threadsize
 buffer_gap = threadsize - frame*(number*2-1)

 spectrum = Array.new
 #処理軽減のためのテーブル作成
 #周波数テーブル作成
 log_table = Array.new
 (frame/2).times{|i|
  log_table[i] = *2*(i+1)
 }

 #ブラックマンハリス窓テーブル作成
 window_table = Array.new
 frame.times{|i|
  if i == 0
   window_table[i] = 0
  elsif i == frame
   window_table[i] = 0
  else
   window_table[i] = (0.35875-0.48829*Math.cos*3**7
  end
 }
 puts "いえい6" + number.to_s
 filename = "lchspectrum" + number.to_s + ".dat"

 lch2spectrum = open(filename, "w")
 lch2spectrum.close
 lch2spectrum = open(filename, "a")

 fft=Fft_lib.new(Math.log(frame.to_f) / Math.log(2.0),1)
 wavs.size.times{ |n|
  if n < frame
  elsif n > (wavs.size - frame)
  elsif n%buffer == 0
   #最後のあまりは0で埋める
   image = Array.new(frame,0)
   lchspectrum = Array.new
   rchspectrum = Array.new
   lchspectrum_real = Array.new
   rchspectrum_real = Array.new
   
   #L/Rで分ける
   x = n - frame
   (frame*2).times{ |i|
    if i%2 == 1
     lchspectrum << wavs[x+i].to_f/bit.to_f
    else i%2 == 0
     rchspectrum << wavs[x+i].to_f/bit.to_f
    end
   }
   #L/Rを合成,ハミング窓をかける
   lchspectrum.size.times{|i|
    x = (lchspectrum[i] + rchspectrum[i])/2
    lchspectrum[i] = x*window_table[i]
   }
   
   #FFT
   fft.fft(lchspectrum,image)

   #frame/2-frameまでは折り返しノイズなのでカット
   (frame/2).times{|i|
    spectrum << *4.to_s)
  elsif ch%2 == 0
   dbr << i*2
   ch2dbr.puts*5.to_s)
  end
  
  #RMS値の計算。44.1kHzで30msになるように設定。非整数倍だと微妙に数値が異なる。
  if ch%(13230*(hz/44100).to_i) == 0
   dbl.each{|f|
    dblsum+=f.abs
   }
   ch2rmsl.puts*6.to_s)
   dbr.each{|f|
    dbrsum+=f.abs
   }
   ch2rmsr.puts*7-20*Math.log10(2**bits)).to_s)
   dblsum=0
   dbrsum=0
   dbl=
   dbr=

  end
  ch+=1
 }
 puts "いえい3"

 #なんかよくわからないけど、配列をそのままgnuplotにぶっこむと、標準出力にデータ区切りが出てしまうのでファイル化
 puts "いえい4"
 ch2dbl.close
 ch2dbr.close
 ch2rmsl.close 
 ch2rmsr.close 
end

db_pararell(ARGV[0],ARGV[1],ARGV[2],ARGV[3],ARGV[4])
 とまぁ、こんな感じでした。ブロマガの表示の都合上、文頭を全角スペースにしているので、コピーする際は気をつけてください。

*1:~num + 1) & [0xff, 0xffff, 0xffffff, 0xffffffff][byte - 1]) if num >> (byte * 8 - 1) == 1 #waveフォーマットはsignedなので変換
   num_data << num #ここ重要!配列に要素を追加するときはpushではなくて<<が早いです。特に本プログラムのように配列にたくさん要素を追加する場合は、<<を使った方が良いです。以下全て<<で配列に要素を追加。
  }
  #全面的にここを参考にしました
 end
 if byte == 4 #byte=4は32bitなので、rubyのunpackが使える
  num_data = data.unpack("i*")
 end
 return num_data
end

#path:String
#waveファイルのファイルパスを受け取って、data層を返す
#ここのソースファイルを活用しました
def filedata(path)
 File.open(path){|file|
  file.binmode
  riff = file.read(4)
  data_size = file.read(4).unpack('V')[0].to_i
  wave = file.read(4)

  if riff != 'RIFF' or wave != 'WAVE'
   puts 'not wave file'
   exit 1
  end

  while !file.eof?
   id = file.read(4)
   chunk_size = file.read(4).unpack('V')[0].to_i
   puts "chunk id: #{id}, size: #{chunk_size}"
   if id == 'fmt '
    format_id = file.read(2)[0].unpack('c')[0]
    channel_num = file.read(2)[0].unpack('c')[0]
    puts $hz = file.read(4).unpack('V').join.to_i
    byte_per_sec = file.read(4).unpack('V').join.to_i
    block_size = file.read(2)[0].unpack('c')[0]
    puts $bit_per_sample = file.read(2)[0].unpack('c')[0]
    #bit深度が16,24,32以外のものははじく
    if !($bit_per_sample == 16 || $bit_per_sample == 24 || $bit_per_sample == 32)
     print "パスサンプル\n"
     exit
    end
   elsif id == "data"
    data = file.read(chunk_size) #音が入っている部分
    data = readInt(data, $bit_per_sample/8) #fmt層で取得したbit深度をbyteにする
    return data
   end
  end
 }
end

filepath = Array.new

#ファイルパスの一覧を取得
Dir::glob("../MUSIC/**/*.wav").each {|f|
 tmp = "#{f}"
 filepath.push(tmp)
}
#ランダムに1つ抽出
filepath = filepath[rand(filepath.size)]

filepath4tweet = filepath.split("/")
#なんかの不具合で元ファイルが壊れたらいやなので、コピー
FileUtils.cp(filepath,"./tmpfile2.wav")
wavs = filedata("./tmpfile2.wav")

#tweetと画像に載せるための文字列作り。一部ディレクトリでライブラリ構造が異なるので、条件分け
if filepath4tweet[2] == "DL"
 tweet = "アーティスト:"+filepath4tweet[3].to_s+",曲:"+filepath4tweet[5].to_s+","+$bit_per_sample.to_s+"bit/"+$hz.to_s+"Hz"
 tweetphoto = "アーティスト:"+filepath4tweet[3].to_s+",アルバム:"+filepath4tweet[4].to_s+",曲:"+filepath4tweet[filepath4tweet.size-1].to_s+","+$bit_per_sample.to_s+"bit/"+$hz.to_s+"Hz"
else
 tweet = "アーティスト:"+filepath4tweet[2].to_s+",曲:"+filepath4tweet[4].to_s+","+$bit_per_sample.to_s+"bit/"+$hz.to_s+"Hz"
 tweetphoto = "アーティスト:"+filepath4tweet[2].to_s+",アルバム:"+filepath4tweet[3].to_s+",曲:"+filepath4tweet[filepath4tweet.size-1].to_s+","+$bit_per_sample.to_s+"bit/"+$hz.to_s+"Hz"
end
#拡張子とgnuplotで不具合の出る"'"を削除
tweetphoto.delete!("'")
tweetphoto.delete!("’")
tweetphoto.slice!(".wav")
tweet.slice!(".wav")

puts tweetphoto

bits = $bit_per_sample.to_i
puts "いえい2"

#gnuplotで波形描写
gp=IO.popen("gnuplot","w");
gp.puts("set title '#{tweetphoto}'")
gp.puts("set terminal png font 'c:/Windows/Fonts/meiryo.ttc,20' size 3000,1500")
gp.puts("set output './waveform.png'")
gp.puts("set multiplot")
gp.puts("unset xtics")
gp.puts("unset ytics")
gp.puts("set xrange[0:'#{wavs.size}']")

#短い時間のファイルは1スレッドで回す
if wavs.size > 441000
 split_size = (wavs.size/7).to_i
 i = 0
 wavs.each_slice(split_size){|e|
  #マルチスレッドで処理するためにファイル化
  filename = "./chwavs" + (i+1).to_s + ".dat"
  wavch = open(filename, "w")
  wavch.puts(e)
  wavch.close
  p e.size
  i+=1
 }
 command1 = "rubyw ./threadform.rb ./chwavs1.dat 1 0 " + bits.to_s + " " + $hz.to_s
 command2 = "rubyw ./threadform.rb ./chwavs2.dat 2 " + split_size.to_s + " " + bits.to_s + " " + $hz.to_s
 command3 = "rubyw ./threadform.rb ./chwavs3.dat 3 " + split_size.to_s + " " + bits.to_s + " " + $hz.to_s
 command4 = "rubyw ./threadform.rb ./chwavs4.dat 4 " + split_size.to_s + " " + bits.to_s + " " + $hz.to_s
 command5 = "rubyw ./threadform.rb ./chwavs5.dat 5 " + split_size.to_s + " " + bits.to_s + " " + $hz.to_s
 command6 = "rubyw ./threadform.rb ./chwavs6.dat 6 " + split_size.to_s + " " + bits.to_s + " " + $hz.to_s
 command7 = "rubyw ./threadform.rb ./chwavs7.dat 7 " + split_size.to_s + " " + bits.to_s + " " + $hz.to_s
 t1 = Thread.start { system(command1) }
 t2 = Thread.start { system(command2) }
 t3 = Thread.start { system(command3) }
 t4 = Thread.start { system(command4) }
 t5 = Thread.start { system(command5) }
 t6 = Thread.start { system(command6) }
 t7 = Thread.start { system(command7) }
 t1.join
 t2.join
 t3.join
 t4.join
 t5.join
 t6.join
 t7.join
 #bit深度に応じてレンジ変更
 gp.puts("set yrange ['#{-(2**bits)}':'#{2**bits}']")
 #波形描写
 gp.puts("plot './chdbl1.dat' notitle with lines lc 1")
 gp.puts("plot './chdbl2.dat' notitle with lines lc 1")
 gp.puts("plot './chdbl3.dat' notitle with lines lc 1")
 gp.puts("plot './chdbl4.dat' notitle with lines lc 1")
 gp.puts("plot './chdbl5.dat' notitle with lines lc 1")
 gp.puts("plot './chdbl6.dat' notitle with lines lc 1")
 gp.puts("plot './chdbl7.dat' notitle with lines lc 1")

 gp.puts("plot './chdbr1.dat' notitle with lines lc 2")
 gp.puts("plot './chdbr2.dat' notitle with lines lc 2")
 gp.puts("plot './chdbr3.dat' notitle with lines lc 2")
 gp.puts("plot './chdbr4.dat' notitle with lines lc 2")
 gp.puts("plot './chdbr5.dat' notitle with lines lc 2")
 gp.puts("plot './chdbr6.dat' notitle with lines lc 2")
 gp.puts("plot './chdbr7.dat' notitle with lines lc 2")
 
 #bit深度に応じてレンジ変更
 gp.puts("set yrange ['#{-20*Math.log10(2**bits)}':'#{20*Math.log10(2**bits)}']")
 #RMS値描写
 gp.puts("plot './chrmsl1.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsl2.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsl3.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsl4.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsl5.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsl6.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsl7.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 
 gp.puts("plot './chrmsr1.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr2.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr3.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr4.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr5.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr6.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr7.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 
 gp.puts("plot 0 notitle with lines linewidth 3 lc rgb 'grey'")
else
 filename = "./chwavs" + (0).to_s + ".dat"
 wavch = open(filename, "w")
 wavch.puts(wavs)
 wavch.close 
 command0 = "rubyw ./threadform.rb ./lchwavs0.dat 1 0 " + bits.to_s + " " + $hz.to_s
 system(command0)

 #bit深度に応じてレンジ変更
 gp.puts("set yrange ['#{-(2**bits)}':'#{2**bits}']")
 #波形描写
 gp.puts("plot './chdbl1.dat' notitle with lines lc 1")
 gp.puts("plot './chdbr1.dat' notitle with lines lc 2")

 gp.puts("unset ytics")
 #bit深度に応じてレンジ変更
 gp.puts("set yrange ['#{-20*Math.log10(2**bits)}':'#{20*Math.log10(2**bits)}']")
 #RMS値描写
 gp.puts("plot './chrmsl1.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
 gp.puts("plot './chrmsr1.dat' notitle with lines linewidth 2.5 lc rgb 'black'")
end
puts "いえい4"
gp.puts("set nomultiplot")
gp.close
#スペクトラム部分
n = 0
if bits == 1
 bit = 32768
elsif bits == 1.5
 bit = 8388608
elsif bits == 2
 bit = 2147483648
end

#buffer:FFT時のサンプルとサンプルの間
buffer = 8192
#frame:FFT時のサンプル数
frame = 16384

bit = 2**bits

#スペクトラム描画の準備
gp=IO.popen("gnuplot","w");
gp.puts("set terminal png font 'c:/Windows/Fonts/meiryo.ttc,20' size 4030,2000")
gp.puts("set output './spectrum.png'")
#FFTの結果がばらつくので、ある程度で収める
gp.puts("set cbrange[0:15]")
gp.puts("set tics out")
gp.puts("unset xtics")
gp.puts("unset cbtics")
gp.puts("unset colorbox")
#Y軸は対数
gp.puts("set logscale y")
gp.puts("set format y ''")
gp.puts("set yrange ['#{($hz/frame.to_f)}':'#{$hz/2.0}']")
gp.puts("set multiplot")
gp.puts("set pm3d map")

#7スレッドで処理する
split_size = wavs.size/7
#あまりが出ないように調整
split_size = buffer*((split_size/buffer).to_i)
#音源の時間が短いと分割できないため条件わけ
if split_size > frame*7
 #X軸の調整
 gp.puts("set xrange[0:'#{split_size*7-frame*14}']")
 i = 0
 wavs.each_slice(split_size){|e|
  #マルチスレッドで処理するためにファイル化
  filename = "./lchwavs" + (i+1).to_s + ".dat"
  wavch = open(filename, "w")
  wavch.puts(e)
  wavch.close
  p e.size
  i+=1
 }
 #FFTの外部プログラム呼び出し
 #filepath:分割したファイルのパス
 #number:何スレッド目か
 #threadsize:分割した際の配列サイズ
 #bit:bit深度による上限値の絶対値
 #frame:FFT時のサンプル数
 #buffer:FFTのサンプルとサンプルの間のサンプル数
 #hz:サンプリングレート
 command1 = "rubyw ./thread.rb ./lchwavs1.dat 1 0 " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 command2 = "rubyw ./thread.rb ./lchwavs2.dat 2 " + split_size.to_s + " " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 command3 = "rubyw ./thread.rb ./lchwavs3.dat 3 " + split_size.to_s + " " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 command4 = "rubyw ./thread.rb ./lchwavs4.dat 4 " + split_size.to_s + " " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 command5 = "rubyw ./thread.rb ./lchwavs5.dat 5 " + split_size.to_s + " " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 command6 = "rubyw ./thread.rb ./lchwavs6.dat 6 " + split_size.to_s + " " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 command7 = "rubyw ./thread.rb ./lchwavs7.dat 7 " + split_size.to_s + " " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz.to_s
 t1 = Thread.start { system(command1) }
 t2 = Thread.start { system(command2) }
 t3 = Thread.start { system(command3) }
 t4 = Thread.start { system(command4) }
 t5 = Thread.start { system(command5) }
 t6 = Thread.start { system(command6) }
 t7 = Thread.start { system(command7) }
 t1.join
 t2.join
 t3.join
 t4.join
 t5.join
 t6.join
 t7.join
 
 #スペクトログラム描画
 gp.puts("splot './lchspectrum1.dat' notitle with pm3d")
 gp.puts("splot './lchspectrum2.dat' notitle with pm3d")
 gp.puts("splot './lchspectrum3.dat' notitle with pm3d")
 gp.puts("splot './lchspectrum4.dat' notitle with pm3d")
 gp.puts("splot './lchspectrum5.dat' notitle with pm3d")
 gp.puts("splot './lchspectrum6.dat' notitle with pm3d")
 gp.puts("splot './lchspectrum7.dat' notitle with pm3d")
 
else #音源ファイルが短い場合は1コアで処理する
 filename = "./lchwavs" + (0).to_s + ".dat"
 wavch = open(filename, "w")
 wavch.puts(wavs)
 wavch.close
 command0 = "ruby ./thread.rb ./lchwavs0.dat 1 0 " + bit.to_s + " " + frame.to_s + " " + buffer.to_s + " " + $hz
 gp.puts("set autoscale x")
 system(command0)
 gp.puts("splot './lchspectrum0.dat' notitle with pm3d") 
end
gp.puts("unset multiplot")
gp.close
puts "いえい8"

#波形とスペクトグラムを合成
image1 = Magick::ImageList.new( "./waveform.png" )
image2 = Magick::ImageList.new( "./spectrum.png" )
image2.crop!(Magick::CenterGravity,300,1500)
image1.concat(image2)
image1.append(true).write('./composite.png')

#ここからツイッター関連
#2014-01-26現在、SSL認証でエラーが起こるので、環境設定でSSL_CERT_FILEを設定する必要あり
#検索で出てくるVerとちょこっとTwitterライブラリでのメソッドが変わってるので注意
CONSUMER_KEY = "**"
CONSUMER_SECRET = "**"
OAUTH_TOEKN = "**"
OAUTH_TOEKN_SECRET = "**"

client = Twitter::REST::Client.new do |config|
 config.consumer_key = CONSUMER_KEY
 config.consumer_secret = CONSUMER_SECRET
 config.oauth_token = OAUTH_TOEKN
 config.oauth_token_secret = OAUTH_TOEKN_SECRET
end

client.update_with_media(tweet,File.new("./test2composite.png"

*2:hz/2)/(frame/2

*3:2*Math::PI*i)/frame)-0.14128*Math.cos((4*Math::PI*i)/frame)-0.01168*Math.cos((6*Math::PI*i)/frame

*4:n+buffer_gap).to_s + " " + log_table[i].to_s + " " + (lchspectrum[i].abs + image[i].abs).to_s)
   }
   spectrum << ""
   lch2spectrum.puts(spectrum)
   spectrum = []
   GC.start
  end
 }
 #なんかよくわからないけど、配列をそのままgnuplotにぶっこむと、標準出力にデータ区切りが出てしまうのでファイル化
 lch2spectrum.close
 puts "いえい7" + number.to_s
end

spectrum_pararell(ARGV[0],ARGV[1],ARGV[2],ARGV[3],ARGV[4],ARGV[5],ARGV[6])

---
threadform.rb

#filepath:分割したファイルのパス
#number:何スレッド目か
#threadsize:分割した際の配列サイズ
#hz:サンプリングレート
def db_pararell(filepath,number,threadsize,bits,hz)

 number = number.to_i
 threadsize = threadsize.to_i
 bits = bits.to_i
 hz = hz.to_i
 filenamedbl = "chdbl" + number.to_s + ".dat"
 filenamedbr = "chdbr" + number.to_s + ".dat"
 filenamermsl = "chrmsl" + number.to_s + ".dat"
 filenamermsr = "chrmsr" + number.to_s + ".dat"

 ch2dbl = open(filenamedbl, "w")
 ch2dbl.close
 ch2dbr = open(filenamedbr, "w")
 ch2dbr.close
 ch2rmsl = open(filenamermsl, "w")
 ch2rmsl.close 
 ch2rmsr = open(filenamermsr, "w")
 ch2rmsr.close

 ch2dbl = open(filenamedbl, "a")
 ch2dbr = open(filenamedbr, "a")
 ch2rmsl = open(filenamermsl, "a")
 ch2rmsr = open(filenamermsr, "a")

 ch = 1
 dbl = Array.new
 dbr = Array.new
 dblsum = 0
 dbrsum = 0

 wav = open(filepath).read
 wavs = wav.split("\n")
 wavs.each{|i|
  i = i.to_i
  
  #Lch,Rch分ける
  if ch%2 == 1
   dbl << i*2
   ch2dbl.puts((ch+(number-1)*threadsize).to_s + " " + (i+2**(bits-1

*5:ch+(number-1)*threadsize).to_s + " " + (i-2**(bits-1

*6:ch+(number-1)*threadsize).to_s + " " + (20*Math::log10(dblsum/dbl.size+1

*7:ch+(number-1)*threadsize).to_s + " " + ((20*Math::log10(dbrsum/dbr.size+1