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





1 件のコメント:

  1. 話の前後を知らないで書き込んですみません。

    めちゃくちゃ昔ですが、普通の?アナログフィルタ、これの出力をVACだかにぶちこんでリズムを切り刻む、なんてのを読んだ事があります。
    まつたけひできだったかなー。
    サンレコでマドンナ?のプロデューサとかもリズムを変態的に刻むために。
    ああ、フィルターの出力をコンプ制御にぶちこむとさらに面白いリズムメイクが出来たとか読んだような。

    まあアナログ時代の技ですねぇ。失礼しました。

    返信削除