2014年11月28日金曜日

簡単な処理でリズム検知したい。



ある程度雑でいいから、マイコンでリズム検知できたらいいなぁ。と思いつつ。


実験。曲によってはビート取り出せる。


とりあえずsoxコマンドで10kHzサンプリングにかえてから



sox input.mp3 -t raw -B -e floating-point -b 32 -c 1 -r 10000 input.raw



以下のソフトに通す。


やってる事は以下の通り




  1. 10このバンドパスフィルタで各周波数帯ごとのエネルギーを取得

  2. 各バンドのエネルギーを掛け合わせる (打楽器系は全周波数帯域にエネルギーが出る)

  3. 積をとったエネルギーの変動具合を、ローパスフィルタとの差分で見る。






#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-
class LPF #ローパスフィルタ
def initialize
@rate=0.99
@outValue=0.0
end
def put(v)
@outValue=(1.0-@rate)*v+@rate*@outValue;
return @outValue
end
end
class BPF #バンドパスフィルタ
def initialize
@inValue=[0.0,0.0]
@outValue=[0.0,0.0]
end
def set(p,c) #ピーク周波数と、フィルタが抽出バンド幅をを指定
@b1=2.0*c*Math::cos(Math::PI*p);
@b2=-c*c
end
def put(v)
o=v - @inValue[1];
o+=@b1*@outValue[0] + @b2*@outValue[1];
@inValue.unshift(v)
@inValue.pop
@outValue.unshift(o)
@outValue.pop
return o;
end
end

data=$stdin.read().unpack("g*")
bpf=Array.new
lpf=Array.new
llpf=LPF.new
lllpf=LPF.new

16.times do |i|
p=1.0/16*i
bpf.push(BPF.new)
bpf[-1].set(p,0.95)
lpf.push(LPF.new)
end
data.each do |d|
dd=Array.new
bpf.size.times do |i|
#各バンドのエネルギーにローパスをかけてdd配列にいれる
dd.push( lpf[i].put(bpf[i].put(d)**2))
end
sum=1.0
dd.each do |v|
sum*=v
end
sum=sum ** (1.0/dd.size())
dd.unshift(sum)
lsum = llpf.put(sum)
v= lsum-lllpf.put(lsum)
puts v

end