HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2011
1223
新山葵マイク音声の入力について10未解決


新山葵

リンク

2011/12/23(Fri) 01:36:08|NO.43891

ガイガーカウンターのパルス(ピッ)音をマイクで入力し、
プログラム側で数えて、リアルタイムで放射線量を計算・記録するプログラムを作っています。

hspwaveを使った波形描画スクリプトを応用して作ったのですが、
PhenomIIやAthlon64 X2のマシンでは上手く動きますが、AtomやCoreDuo U2400など
性能の低いCPUでは計算や音声分析の間に音声入力に空白が発生して処理落ち(パルス音の取りこぼし)が発生します。

ネットブックで屋外で使うのを想定していたので知恵を貸してください。


#include "hspwave.as" sdim buf,44100 w_in_open 8000,8,1 w_in_add buf,640,1 repeat repeat ;バッファがいっぱいになるのを待つ w_in_bufs bufs if bufs==0 :break await 0 loop repeat 640 c=peek(buf,cnt) if c<64:count+1 ;cが64未満だったらカウントとする loop w_in_add buf,640,0 ;2回目以降 gosub *calc loop *calc cls mes "振幅"+c+"\nカウント="+count ;計算、画面表示する return


また、mciで1秒程度録音しファイルに出力、再度録音コマンドを出し、次を録音する間にファイルを読んで分析という作業を繰り返す・・・という
事も考えて試してみたのですが、mciコマンドから実行まで時間が掛かる?のか、こちらは壮絶に取りこぼします。

ガイガーのパルスが数ミリ〜十数ミリ秒程度で短いので、少しの音声入力の切れ目でも取りこぼしの原因になってしまうのですが、
何か良い入力方法は無いでしょうか?



この記事に返信する


XBG|YAMANOTE231103(携帯端末)

リンク

2011/12/23(Fri) 12:59:12|NO.43895

音で計測するというのは誤認識の可能性も考えられますが、、、

バッファの待ち処理の後の640回のループは恐らく計測部分でしょうか、
とりあえず*calcのところで画面表示を行っているので、
この部分ではCPUの性能の差は避けられません。
スクリプトだけではこの問題の解決は難しいでしょうか、、、

それと、4行目からプログラム全体のループ処理を行っていますが、
ここだけはgotoで戻るという形にした方がよいです
このままだとたびたび落ちることがありますので。



てれてれ

リンク

2011/12/23(Fri) 14:22:37|NO.43897

>ここだけはgotoで戻るという形にした方がよいです
>このままだとたびたび落ちることがありますので。
初耳でした。
でも何故落ちるのですか?



通りすがり

リンク

2011/12/23(Fri) 17:16:00|NO.43899

HSPに標準で付属しないプラグインに付いて聞く場合は
試すことが出来る様にせめてそのファイルの入手先を書いた方が良いです。
(一番良いのはその作者に聞く事だと思いますが)

>>このままだとたびたび落ちることがありますので。
>でも何故落ちるのですか?
話半分で良いと思います。



XBG|YAMANOTE231103(携帯端末)

リンク

2011/12/23(Fri) 17:38:09|NO.43900

話半分にとのことですが今後のために理由を

落ちる、というのはgosubを繰り返すことで回帰に関する処理が徐々に複雑になり(?)、
結果として「ネストが深すぎます」のエラーが返ってくることがあるためです
そこでgotoを使うことで以降の回帰処理をリセットしてあげます

自分もrepeatからのgosubの繰り返しで落ちたことがあります、、、

音の取りこぼしについての本題ですが、残念ながらCoreDuo環境が手元にないので
申し訳ありませんが後は他のみなさまにお任せします。



晩御飯

リンク

2011/12/23(Fri) 18:37:07|NO.43901

やっぱり話半分で良さそうだなあ

ものすごくざっくり説明するとネストっていうのはプログラムの深さことで、
gosubとかrepeat-loopとかifなどを使う度にネストは深くなっていく
このネストが深くなりすぎると落ちてしまうんだけど
きちんとそのループや分岐から抜けてやればネストが深くなりすぎることもないし落ちない
// ネストなし
repeat N // ネスト一重 repeat N // ネスト二重 loop // ネスト一重 loop // ネストなし
ただそのネストから抜けるのが上手くいってないと落ちてしまう
*a
repeat goto *b // ネストを抜けていないのでgotoする度にネストが深くなる loop *b goto *a
repeat-loopから抜けるのにgotoを使ってたりgosubから飛んだ先にreturnが無かったりすると危ない

なんか説明とか例とか適当だけどきっと誰かが補完してくれるはず

>そこでgotoを使うことで以降の回帰処理をリセットしてあげます
リセットされない。gotoでのループはネストが増えないってだけ



Cookies

リンク

2011/12/23(Fri) 23:04:02|NO.43902

ちなみにいっておくと
looplevとsublevというシステム変数があり、(デバッグウィンドウで確認可)
それぞれrepeat/loopとgosub/returnを管理していると思われる。
looplevは31でエラー表示され、sublevは513でエラー表示される。
looplevは「ネストが深すぎます」と言われ、sublevは「スタック領域のオーバーフローです」とかいわれる。

ifのネストは初めて聞いたが、確認できなかった。


当初の質問に全然回答してませんね。すみません。



なたで

リンク

2011/12/24(Sat) 08:09:34|NO.43905

調べる間隔を減らせば、計算量は減ると思います。

>ガイガーのパルスが数ミリ〜十数ミリ秒程度で短い
波形の流れている時間長を5msだとすると、
5msの時間長は400Hzぐらいのサンプリング周波数があれば検知できると思います。
5ms = 200Hz → サンプリング周波数400Hz

サンプリング周波数を8000Hzで録音したデータで、
fs = 8000
intervalms = 5
int(intervalms/(1000f/fs)) = 40
から、40サンプル飛ばしで調べればいいことが分かります。

ただし、間隔によっては折り返し歪が発生して音が検出できない場合があります。

例えば、ガイガーカウンターのパルスの音なんですが
下の動画のガイガーカウンターの場合は、波形の基本周波数は3300Hz
http://www.youtube.com/watch?v=5Jf0w35dCeg

これを基準に考えると、
3300Hz \ 400Hz = 100Hz
により、0Hzではないので、折り返し歪が発生しても収録できるとおもいます。

折り返し歪
周波数が0Hzから1000Hzの音を収録したい場合は、
2倍の2000Hzでサンプリングしないといけません。
サンプリング周波数が2000Hzの場合、
1100Hzの音は記録できず100Hz分だけ折り返して、
900Hzの音として記録されます。
だからもしも、基本周波数が2000Hzの音を記録すると、
折り返しで基本周波数が0Hzの音として録音されるので収録ができません。
2200Hzなら、1000Hzで1度折り返して、
0Hzで再び折り返して、200Hzの音になるはず。


#include "hspwave.as" #define threshold 1000 //これより大きければ検出 #define fs 8000 //0から4kHzまでの信号をサンプリング #define intervalms 5.0 //調べる間隔[ms] #define bufferms 100.0 //バッファ[ms] #define byte 2 //量子化サイズ(16bits) //時間をポイントに変更 buffersize = int(bufferms/(1000f/fs))*byte //調べる間隔 intervalpoint = int(intervalms/(1000f/fs)) //調べる回数 loopa = buffersize / (intervalpoint*byte) w_in_open fs,byte * 8,1 //初期化 sdim buf,buffersize * 10 w_in_add buf,buffersize,1 repeat repeat w_in_bufs state:if state==0 :break await 0 loop number = 0 repeat loopa c = wpeek(buf,number) if c & 0x8000: c -= 0x10000 if abs(c)>threshold:count++ number += intervalpoint * byte loop w_in_add buf,buffersize,0 gosub *calc loop *calc color 255,255,255:boxf 0,0,300,300:color:pos 0,0 mes "振幅"+c+"\nカウント="+count return



HK2

リンク

2011/12/24(Sat) 10:39:23|NO.43907

gotoに関して。

命令 goto でのジャンプはリターン情報をリセットしませんが、
割り込み命令のキーワードとしての goto はリターン情報をリセットします。

HDLには書いていませんが、マニュアルには書いています。



新山葵

リンク

2011/12/24(Sat) 17:36:40|NO.43911

みなさんありがとうございます。

hspwaveはびんずめ堂さんのPCM入出力プラグインです。
http://www.binzume.net/software/forhsp.html

波形描画のスクリプトはここから手に入れました。
http://hsp.tv/play/pforum.php?mode=pastwch&num=39796

CoreDuoといってもU2400(超低電圧版)なので、コアあたりの性能はAtomと同じくらいです。
仕組み上、PhenomIIのマシンでも空白時間は存在するはずですが、こちらでは問題なく動くんですよね。

分析ループする毎にインクリメントする適当な変数を入れ
合計を稼働時間で割れば一秒あたりの処理数が出ますが、一秒間に7900/8000以上処理できています。

一方で、Atomのマシンだと7000/8000以下で100ms以上の空白時間が発生するようです。


>>なたで さん
ありがとうございます。
確かに、飛ばし分析した方が低負荷になりますね。参考になります。

あと、この条件式はどういう意味しょうか?
> if c & 0x8000: c -= 0x10000
もし、(?) ならば c=c-65536

先ほどサンプリングレートを下げる事も試したのですが、分析ループをコメントアウトした最小限の状態でも
5800/6600程度しか処理出来ず、やはり100ms程度の処理落ちが発生するようです。

という事は、計算等で処理落ちしているわけでは無い・・・?
ひょっとしたらプラグインの使い方が悪いのでしょうか。
何だかよく分からなくなってきました。



なたで

リンク

2011/12/26(Mon) 20:43:32|NO.43942

>先ほどサンプリングレートを下げる事も試したのですが、
サンプリングレートを調節する部分は2か所あります。


#include "hspwave.as" #define threshold 1000 //これより大きければ検出 #define fs 8000 //0から4kHzまでの信号をサンプリング #define intervalms 5.0 //調べる間隔[ms] #define bufferms 100.0 //バッファ[ms] #define byte 2 //量子化サイズ(16bits) //時間をポイントに変更 buffersize = int(bufferms/(1000f/fs))*byte //調べる間隔 intervalpoint = int(intervalms/(1000f/fs)) //調べる回数 loopa = buffersize / (intervalpoint*byte) w_in_open fs,byte * 8,1 //初期化 ←サンプリングレート調節【1】 sdim buf,buffersize * 10 w_in_add buf,buffersize,1 repeat repeat w_in_bufs state:if state==0 :break await 0 loop number = 0 repeat loopa c = wpeek(buf,number) if c & 0x8000: c -= 0x10000 if abs(c)>threshold:count++ number += intervalpoint * byte ←サンプリングレート調節【2】 loop w_in_add buf,buffersize,0 gosub *calc loop *calc color 255,255,255:boxf 0,0,300,300:color:pos 0,0 mes "振幅"+c+"\nカウント="+count return

1か所目は、hspwaveの渡す命令の部分で、
ここでは、音の取り込む周波数帯域によって制限があります。
youtubeの例だと、基本周波数(音の周期)は3300Hzなので、
サンプリング周波数は6600Hzまで下げることが出来ます。
ここで指定すると、
サンプリング周波数÷2 Hz以上の音はローパスフィルタでカットされます。
ですので、下げすぎると多分音を認識できなくなるので注意。

2か所目は、自前でサンプリング周波数を変更している部分です。
こちらは、ローパスフィルタをかけていないので、
ここでのサンプリング周波数 ÷ 2Hz以上の音は折り返し歪となります。
折り返し歪は、前の書き込みの通りで、
折り返しがうまい具合に調節されていれば、問題ありません。

それで、例えば1か所目を最大限の6600Hzに設定(今回変更を加えた)とすると、
これはhspwaveの機能の部分なので、
w_in_add,w_in_bufs などのhspwaveの関数部分が
以前より高速化に動作すると考えられますが、
この部分はhspwaveの機能なので、速度的にはあまり変化は見られないと思います。
また 2か所目は、
intervalpoint = int(intervalms/(1000f/fs))
loopa = buffersize / (intervalpoint*byte)
によって計算されているので、
HSPのコード上の計算回数は相殺されるはずです。

というわけで、
サンプリング周波数は前回のソースコード以上いじれる部分は
そんなにないと思いました。

ただ、前回のソースコードは40サンプル飛ばしをしているので、
単純に考えると元のコードよりは、40倍速くなっているはずです。
これで重いとなると別の原因があるのかなって思います。


c = wpeek(buf,number) if c & 0x8000: c -= 0x10000 if abs(c)>threshold:count++
値の精度が256通り(-128から127)だと、調節がしにくいかなと思い
65536通り(-32768から32767)つまり
量子化ビット数を8ビットから16ビットに増やしました。
ですので、値を16ビット符号付き整数型で抜き出している部分です。
if c & 0x8000 は、 if (c & 0x8000) != 0 の略です。すみません。
これは、符号付き整数型の場合は、負の数は2の補数表現で表します。
ググってみると分かると思います。
それで、16ビット目が1であるかどうかを調べています。
それで負の数なら32ビット符号付き整数型(HSPのint)に調節しています。
最初に新山葵さんが示したサンプルコードのように
量子化ビット数8ビットの方が速度は速くなると思います。

>一方で、Atomのマシンだと7000/8000以下で100ms以上の空白時間が発生するようです。
>5800/6600程度しか処理出来ず、やはり100ms程度
両方とも同じぐらいなので、
やはり何かほかに問題があるような気がします。

ところで
>分析ループする毎にインクリメントする適当な変数を入れ
>合計を稼働時間で割れば一秒あたりの処理数が出ますが、
>一秒間に7900/8000以上処理できています。
この辺をどうやってやってますか。
分析ループ中に時間が間に合わなければループを抜ける処理をやっているのでしょうか。
時間の測定方法は、timeGetTimeとかGetTickCountとか使っているのですか。
余りにも短い時間なので誤差によって正確に計算できない可能性があると思います。



ONION software Copyright 1997-2023(c) All rights reserved.