2014年12月29日月曜日

Ruby Mechanize の文字コードエンコーディング変換



最近はやり方が大部スマートになってるんですね。


encoding変換部分がフックできるようになっているのでそこでUTF-8に変換すれば良いだけです。


jpegだとかを間違って処理しないようにtextという文字をContent-Typeに含む物だけを変換しています。


コンテンツ本体は、body_ioを使ってファイルストリームのように扱います。



require 'mechanize'
require 'nkf'

agent = Mechanize.new

agent.content_encoding_hooks << Proc.new do |s, uri, response, body_io|
if %r|text/html| =~ response["Content-Type"]
body_io.rewind #念のため巻き戻し(多分不要)
tmp=NKF.nkf("-Ewm0",body_io.read);# readで読み込んでEUCからUTF-8にnkfで変換
tmp.force_encoding("utf-8");
body_io.rewind #巻き戻して、utf-8で書き直す
body_io.write(tmp);
response["Content-Type"]="text/html; charset=utf-8"
end
end





2014年12月10日水曜日

WMVファイルの作成日時を調べる



ファイルプロパティヘッダに1601/1/1から100ナノ秒単位で数えた秒数が入っているので、それを計算すればOK。



#!/usr/local/bin/ruby
require 'date'
data=$stdin.read(4096);
pos=data.index(["A1DCAB8C47A9CF118EE400C00C205365"].pack("H*")) + 16*3;
puts Date.new(1601,1,1) + data[pos,8].unpack("Q")[0] * 1e-7 / 60 / 60 / 24


参考にしたサイトは↓(時刻の計算方法が書いてないので注意)


http://uguisu.skr.jp/Windows/format_asf.html





MP4,movファイルの日付



mp4box(gpac-mp4box)をインストールした上で以下のコマンドでファイル日付が得られる



mp4box -std -diso 調べたいファイル名 |grep Creation|ruby -ne 'd=$_.split(/\"/)[1]; puts Time.at(d.to_i + Time.local(1904).to_i ).to_s.split[0];exit'






2014年12月5日金曜日

バンドパスフィルタをHW化すれば8bitマイコンでもいけそう。



しなぷす さんに教えて貰ったMSGEQ7というバンドパスフィルタを使えば前回いっていたリズム検知が簡単に実装できそうなのでためしてみた。(実チップでの処理ではなくデータシートから読み取ったインチキシミュレータです)


https://www.switch-science.com/catalog/585/


初音ミクの「イノセンス」のサビ部分(83秒付近)を処理するとこんな感じ、サビに入る部分はリズムがちょっとつぶれてるけど、それ以外はリズムが取れてる。リズムで電飾光らせるぐらいなら、十分だと思う。


f:id:akira_you:20141205061246p:image


横軸の単位は(秒)です。


赤線が積を取った信号(ちょっと正規化してるけど)。緑線はそれにさらにローパス(立ち上がりのみローパスなし)フィルタをかけたもの。


緑と赤が共にぎゅんと上がって、その後離れる点をビート点とすればよさそう。





マイコン側の処理は以下のように5チャンネル分の積をとって正規化するのと、ローパスのみ。これを100Hz周期で繰り返す事を想定してます。100Hz周期で取ってくるのでMSGEQ7の63Hzや130Hzバンドは信用できない状況になっているのでとりあえずデータを捨てています。



class LPF
def initialize
@rate=0.9
@outValue=0.0
end
attr_accessor :rate,:outValue;
def putp(v)
@outValue=v if(@outValue<v)
@outValue=(1.0-@rate)*v+@rate*@outValue;
return @outValue
end
end
#
#(略)以下メインループ
#
#ここでretにMSG7EQの出力が入る
m=1.0
a=0.0
ret[-5..-1].each { |r| m *= r ;a+= r} #低周波はあまり信用できないはず
v=m
v=m/(a**2 + 1.0E-100) #綺麗に正規化まではしない。音量と相関値との中間ぐらいの特徴量
r=[v,llpf.putp(v)] #ここで出力信号が入る
puts r.join("\t")






実験コード





#!/usr/local/bin/ruby19
# -*- coding: utf-8 -*-
#データの前処理は以下の通り
#sox input.mp3 -t raw -B -e floating-point -b 32 -c 1 -r 96000 input.raw

'In maxima
F:96000;
C:0.1;
H(z,p,c):=(z-1)*(z+1)/((z-c*exp(p*%i*%pi))*(z-c*exp(-p*%i*%pi)))*p;
define(G(f,p,c), 10*log(10)*log(abs( H(exp(-1*%i*2*%pi*f/F),2*p/F, 1- (1-C)*p/F*2 ))));
plot2d([G(x,63,C),G(x,160,C),G(x,400,C),G(x,1000,C),G(x,2500,C),G(x,6250,C),G(x,16000,C)] , [x,20,22000],[logx]);


係数
a0: 1
a1: 0
a2: -1
b1: 2*c*cos(%pi*p)
b2: -c^2
'

class LPF
def initialize
@rate=0.9
@outValue=0.0
end
attr_accessor :rate,:outValue;
def put(v)
@outValue=(1.0-@rate)*v+@rate*@outValue;
return @outValue
end

def putp(v)
@outValue=v if(@outValue<v)
@outValue=(1.0-@rate)*v+@rate*@outValue;
return @outValue
end
end
class BPF
def initialize
@N=2
@inValue=[0.0,0.0]
@outValue=[0.0,0.0]
end
def set(p,c)
#$stderr.puts "set p=#{p} c=#{c}"
@b1=2.0*c*Math::cos(Math::PI*p)
@b2=-c*c
@gain=p
end
def out()
return @outValue[0]*@gain
end
def put(v)
o= v - @inValue[1] + @b1*@outValue[0] + @b2*@outValue[1]
@outValue[1]=@outValue[0]
@inValue[1]=@inValue[0]
@outValue[0]=o
@inValue[0]=v
return o * @gain;
end
end
class MSG7
def initialize
@F=96000.0
@C=0.1
@BINSIZE=@F/100; #30Hzで取り込むなら @F/30を指定
@count=0
@bpf=Array.new
[63,160,400,1000,2500,6250,16000].each do |f|
p= 2*f/@F;
c= 1- (1-@C)*f/@F*2
@bpf.push(BPF.new)
@bpf[-1].set(p,c)
end


@lpf=Array.new
@bpf.size.times { @lpf.push(LPF.new) }
@peak=Array.new
@peak.fill(0.0,0,@bpf.size())
end
def put(v)
@bpf.size.times do |i|
tmp=@bpf[i].put(v).abs
@peak[i]=tmp if(@peak[i]<tmp)
end
@count += 1
return nil if @count < @BINSIZE


ret=Array.new(@bpf.size)
@bpf.size.times do |i|
ret[i]=@lpf[i].putp(@peak[i]);
end
@peak.fill(0.0,0,@bpf.size())
@count=0
return ret
end
end

msg=MSG7.new
llpf=LPF.new
llpf.rate=0.85

while(true) do
data=$stdin.read(4*96000/10)
break if (data==nil)
data.unpack("g*").each do |d|
ret=msg.put(d)
next if ret == nil
#ここでretにMSG7EQの出力が入る
m=1.0
a=0.0
ret[-5..-1].each { |r| m *= r ;a+= r} #低周波はあまり信用できないはず
v=m
v=m/(a**2 + 1.0E-100) #綺麗に正規化まではしない。音量と相関値との中間ぐらいの特徴量
r=[v,llpf.putp(v)]
puts r.join("\t")
end
end