Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

音量の取得方法

質問失礼致します、PCのマイク入力端子経由に接続した
マイクからの音声を常時取得し、その音量を常時表示す
るプログラムを組みたいのですが上手く動作しません。

getLevel()メソッドを利用し、float型の変数でその数
値を保持したいのですが、値は『-1.0』となってしま
い、正常値を返さないのです。(正常であれば0.0〜1.0
の間でfloat型の数値を返すはずなのですが・・)

以下、書いたコードを記載致します。(書いたソースで
は常時ではなく、for文で10000回取得するようにしてあ
ります)

皆様お忙しい中本当に申し訳ないのですが、どこがいけ
ないのか、またどうすれば意図した動作になるのか、ご
教授頂けますでしょうか。

宜しくお願い致します(^-^)


import java.io.*;
import javax.sound.sampled.*;

public class MicrophoneIn2
{
        public static void main(String[] args)
        {

                try
                {
                        System.out.println("入力開
始");
                        
                        AudioFormat linearFormat = 
new AudioFormat(8000,16,1,true,false);
                        
                        // ターゲットデータライン
を取得する
                        DataLine.Info info = new 
DataLine.Info(TargetDataLine.class,linearFormat);
                        TargetDataLine 
targetDataLine = 
(TargetDataLine)AudioSystem.getLine(info);
                        
                        // ターゲットデータライン
をオープンする
                        
targetDataLine.open(linearFormat);
                        targetDataLine.start();

                        // 
ボリュームレベルを常時取得し続ける
                        
for (int i = 0; i < 10000; i++) {

                            
float x = targetDataLine.getLevel();
                            
System.out.println(x);
                            
try { Thread.sleep(10); } catch 
(InterruptedException e) {}

                        }
                        
targetDataLine.stop();
                                                
                        // ターゲットデータライン
をクローズ
                        targetDataLine.close();
                        
                        
                        System.out.println("取得完
了");
                }
                catch(Exception e)
                {
                        e.printStackTrace();
                }
        }

}

5

回答

16494

閲覧

5件の回答

評価

0

追記:ソース上の『import.java.io.*;』は消し忘れです
のでお気になさらないで下さい(^-^;)

評価

30

-1はAudioSystem.NOT_SPECIFIEDの値ではないだろうか。

そのコードを実行してみたところ、バッファにデータが溜まっていることは確認できたが、レベルの取得ができない理由はわからなかった。すまぬ。

評価

30

どうやら getLevel は実装されていないようです。
データーを読み込んで計算しましょう。
レベルの計算は 16 bit オーディオならそのサンプル値を short として、32768.0 で割って二乗して一定数足し合わせて平均を出し平方根を取ります(RMS)。対数を使えばデシベルにも出来ます。

評価

0

>>匿名さん

確かに-1はAudioSystem.NOT_SPECIFIEDのようです、恐
らくありえない値が返ってきているのでしょうね(^-^;)

いえそんな、ご丁寧にバッファのデータまでご確認頂い
て本当にありがとうございました(^-^)


>>仙人さん

getLevelは実装されていないのですね、とても使い易そ
うだっただけにちょっぴり残念です(^-^;)

そして具体的な計算方法までお教え下さって本当にあり
がとうございます(^-^)

getLevelを使えないとの事ですので、仰る通りデータを
読み込んで計算したいと思っているのですが…すみませ
ん、数学知識とbit知識がさっぱりな為、仰って下さっ
ている事の半分も理解出来ていないのです(^-^;)

データ計算をする下準備のイメージとしてはまず…

//データ読み込み用のbyte配列を用意
byte[] voiceData = new byte[1600];

// ターゲットデータラインをオープン
targetDataLine.open(linearFormat);
                
targetDataLine.start();

// ターゲットデータラインから入力ストリームを取得
する
AudioInputStream linearStream = new 
AudioInputStream(targetDataLine);

// 入力ストリームから音声データをByte配列へ                
linearStream.read(voiceData,0,voiceData.length);

といった流れでよろしいのでしょうか?

そしてその後で

// Short型変数にbyte配列の中身を代入
Short st = 0;
  for(int i = 0; i < voiceData.length; i++) {

     st = st + voiceData[i];

  }

のような流れでよろしいのでしょうか?

また、仰って下さっている二乗の部分はマイナス値をプ
ラス方向にという事なのかなと思っているのですが、
32768.0で割る部分がどうしてそういう処理をするのか
全く検討もついておりません、すみません(^-^;)(もし
かしてshort型で扱える数字が-32768〜32768という事と
関係しておりますでしょうか?)

質問だらけで本当に申し訳ないです、とても勉強になり
ますのでお手空きの時にでもお教え頂けますでしょう
か。ぜひ宜しくお願い致します(^-^)

評価

30

2バイトから数値にするのは
((voiceData[i]<<8)|(voiceData[i+1]&0xff))
i は 2 ずつ進めるて下さい。
32768.0 で割ると結果が最大 1.0 になります。
縮尺みたいなもんですから具合のいい数にしてかまいません。
二乗の平均の平方根は物理的な大きさを求めてますので
だいたい聞こえる音の大きさにマッチします。
他には、電気的録音を考えた場合は一定期間の絶対値の最大(ピークメーター)賭する方がいい場合もあります。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。