Androidで音声認識を。

考えてみたらAndroidネイティブで何か作るってやってなかったなぁ。そういうのはAdobe AIRでお茶を濁してたからね。 そんなわけで、Androidで遊んでみる。 うん、いかにもAndroidな「音声認識」をやってみようか。

NetBeansでAndroidプロジェクト作って、以下のようにしてみた。

参考にした記事

元の記事
http://www.adakoda.com/android/000164.html

eclipse用とおもいますけど差異はありません。また色が気に入らなかった問題、この後に音声合成と組み合わせたい事、あと、結果を単につないでトースターで表示するだけって部分はちょっとアレだったんで、そこには手を加えました。

MainActivity.java *

package com.example.soundtest;

import java.util.ArrayList;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.HashMap;

public class MainActivity extends Activity
{

    // 文字配列の中から有意なひとつを選び出す。
    // ロジック(要素が2つ以上の時):
    // a)全てがユニークな時は0番めのものを選ぶ。
    // b)ユニークでないのがある場合、その最大値のものを選ぶ。
    private String getUnique(ArrayList<String> s){
        HashMap<String,Integer> map = new HashMap<String,Integer>();
        int z = 0;
        int max = 0;
        String xmax = "";
        String r = "";
        // 配列が一件のみならその一件をセット。
        if(s.size() == 1){
            r = s.get(0);
        }else{
            // ユニーク性調査
            for (int i = 0; i< s.size(); i++) {
                if(map.get(s.get(i)) == null){
                    // 何も設定されていない。
                    z = 1;
                    map.put(s.get(i),z);
                }else{
                    // 既にあるから加算しよう。
                    z = map.get(s.get(i))+1;
                    map.put(s.get(i),z);
                }
                // 最大値が更新されていたらセット。
                if(z > max){
                    max = z;
                    xmax = s.get(i);
                }
            }
            // 最大値は1か2以上か?(ユニーク性調査)
            if(max < 2){ // 全部ユニークなら最初のものを。
                r = s.get(0);
            }else{ // ユニークでないのが存在するなら最大値のものを。
                r = xmax;
            }
        }
        return r;
    }

    // = 0 の部分は、適当な値に変更してください(とりあえず試すには問題ないですが)
    private static final int REQUEST_CODE = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button button = (Button) findViewById(R.id.button); // アクティビティ上のボタンを割り振る。

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    // インテント作成
                    Intent intent = new Intent(
                            RecognizerIntent.ACTION_RECOGNIZE_SPEECH); // ACTION_WEB_SEARCH
                    intent.putExtra(
                            RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                            RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
                    intent.putExtra(
                            RecognizerIntent.EXTRA_PROMPT,
                            "はい、どうぞー (`・ω・´)ゞ");

                    // インテント発行
                    startActivityForResult(intent, REQUEST_CODE);
                } catch (ActivityNotFoundException e) {
                    // このインテントに応答できるアクティビティがインストールされていない場合
                    Toast.makeText(MainActivity.this,
                        "ActivityNotFoundException", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    // アクティビティ終了時に呼び出される
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        TextView vv = (TextView) findViewById(R.id.kekka); // これでアクティビティのそれと関連づけて動作させるん。
        TextView vvf = (TextView) findViewById(R.id.flag); // これでアクティビティのそれと関連づけて動作させるん。
        TextView vvv = (TextView) findViewById(R.id.kekka2); // これでアクティビティのそれと関連づけて動作させるん。

        // 自分が投げたインテントであれば応答する
        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
            String resultsString = "";
            String result2 = "";

            // 結果文字列リスト
            ArrayList<String> results = data.getStringArrayListExtra(
                    RecognizerIntent.EXTRA_RESULTS);

            for (int i = 0; i< results.size(); i++) {
                // ここでは、文字列が複数あった場合に結合しています
                if(i == 0){
                    resultsString = results.get(i);
                }else{
                    resultsString = resultsString + "  " + results.get(i);
                }
            }
            // ユニーク調査
            result2 = getUnique(results);

            // トーストを使って結果を表示
            //Toast.makeText(this, resultsString, Toast.LENGTH_LONG).show();

            // set Result
            if(results.size() == 1){
                vv.setText(resultsString);
                vvf.setText("");
                vvv.setText("");
            }else{
                vv.setText(result2);
                vvf.setText("複数あったので選択(オリジナルは以下)");
                vvv.setText(resultsString);
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background"
    >

<Button
    android:id="@+id/button"
    android:text="Click to start"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background"
    >

        <TextView
            android:id="@+id/kekka"
            android:paddingTop="40px"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/forground"
            android:gravity="center"
            android:text="結果" />

        <TextView
            android:id="@+id/flag"
            android:paddingTop="40px"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/forground"
            android:gravity="center"
            android:text="" />

        <TextView
            android:id="@+id/kekka2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/forground"
            android:gravity="center"
            android:text="" />

    </LinearLayout>

</LinearLayout>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="background">#ccffcc</color>
    <color name="forground">#000000</color>
</resources>

うん。いやぁ結構わかりやすいですねAndroid。うむ。