
| ★はじめに★ |
![]() |
第7話 音声認識機能を使ったVアプリを作る [JAVA PRESS Vol.34] ゲーム:こたえて!そらみ 対応端末:V601SH・J-SH53
|
![]() |
へにへに〜、大変大変っ!ボーダフォンの契約純増数は今月も超閑古鳥なのっ!これじゃあauに差を付けられる一方だよぅ! | |
| 前々回さんざん酷いこと言ってたくせに、なんで今さらボーダフォンの心配してるのさ、そらみちゃん…。まあ、ツーカーみたいに契約数がマイナスになってないだけマシじゃない? | ![]() |
|
![]() |
今まで企業しか作れなかった50Kや256Kアプリの開発環境もやっと一般公開されたし、テレビ見れたり犬とおしゃべりできたりする端末だって出たし、 近ごろようやく面白くなってきたんだけどなぁ…。 |
|
| 社名が海外産のマイナーくさいのに変わっちゃっただけに、社名ールで築き上げたブランド力もすっかり落ちぶれちゃったんだよ…。 | ![]() |
|
![]() |
座布団没収。そんなことより、ボーダフォンのVアプリ作ろうよぉ〜。今のボーダフォンって、ハードメーカー末期のSE○Aみたいな必死さで胸がキュンキュンうずいちゃうのぉ〜! | |
| はいはい。そらみちゃんがいかに腐女子かってことはよく分かりました。それじゃあ、ボーダフォンならではの音声認識機能を使って、そらみちゃんと会話するゲームを作ってみるのはどうかな? | ![]() |
|
![]() |
いわゆる『シー○ン』とか『ピ○チュウげんきでちゅう』みたいなのかな?そんなことまでできるなんて、やっぱりボーダフォンって無駄にスゴイよね。目の付け所がシャープ(のみ)だよねっ! | |
| ………何はともあれ、作ってみよっか(汗) | ![]() |
| ★Vアプリ★ |
Vアプリ
NTTドコモの携帯電話のWeb閲覧サービスを「iモード」、アプリのダウンロードサービスを「iアプリ」と呼ぶのに対し、ボーダフォンの携帯電話のWeb閲覧サービスを「ボーダフォンライブ!」、アプリのダウンロードサービスを「Vアプリ」と呼びます。「Vアプリ」は以前「Javaアプリ」と呼ばれていましたが、J-PHONEからボーダフォンへの社名変更に伴い変更されました。
WEB閲覧サービス アプリのダウンロードサービス NTTドコモ iモード iアプリ ボーダフォン ボーダフォンライブ! Vアプリ au EZWeb EZアプリ
MIDPとJSCL
「MIDP(Mobile Information Device Profile)1.0」は、ボーダフォンやauの携帯電話をはじめとする多くの携帯端末で採用されているJavaのAPI仕様です。携帯電話だけでなくPDAまでも視野に入れて設計されています。
しかし、携帯端末の進化ははやく、MIDP1.0の仕様だけではアプリ作成には不十分なため、Vアプリには「JSCL(J-PHONE Specific Class Libraries)」と呼ぶ拡張APIが用意されました。「JSCL」には「JSCL1.0」「JSCL1.1」「JSCL1.2」の3つのバージョンがあり、旧Jフォン端末では,「JSCL1.0」を採用している端末を「C4型」、「JSCL1.1」を採用している端末を「P4型」、「JSCL1.2」を採用している端末を「P5型」と呼びます。ボーダフォン端末ではこれらの型名を使わなくなりましたが、「V601N」と「V801SA」はP4型、「V601SH」はP5型相当の機能を持っているので、表に含めています。
主な拡張機能は次の通りです。
- スプライト
ゲームのキャラクターを軽快に動かすことができます。- 3Dポリゴン
3Dポリゴンのキャラクターを表示することができます。- デバイスコントロール
電池残量、電界強度、位置情報、キー押下状態を取得できます。また、バックライトやバイブレータも制御できます。- 音の再生
音を鳴らすことができます。使用できるファイル形式はSMD(*.smd,*.smz,*.smx)、SMAF/MA2(*.mmf)、SMAF/MA3(*.mmf)、SMF/Phrase(*.spf)で、複数の音が同時に鳴らせるのはSMF/Phrase(*.spf)のみです。- 待ち受けアプリ
待ち受けアプリを作成することができます。待ち受けアプリとは、待ち受け画像のように携帯電話に常駐するアプリのことです。「音声着信があった」、「メール受信があった」などの情報も取得することができます。- 音声認識
音声を認識して、声に反応するアプリを作れます。- ブラウザやメーラとの連携・音声通話連携
アプリからブラウザやメーラーを起動したり、電話を掛けたりする
各JSCLにおいて拡張された機能 型 拡張API 対応機種 前JSCLからの拡張点 C4型 JSCL1.0 J-SH07/J-T06/J-D05/J-D06/
J-N04/J-N05/J-SH08/J-SH09/
J-T08/J-SH010/J-D08/J-T010/
V401SH- P4型 JSCL1.1 J-SH51/J-K51/J-T51/J-P51/
J-SA51/J-SH52/J-N51
V601N/V801SA圧縮データの復元 P5型 JSCL1.2 J-SH53
V601SH音声認識
ブラウザやメーラとの連携
音声通話連携
赤外線通信・赤外線リモコン
カメラ・コードリーダー制御など
| ★開発環境を整える★ |
今回のゲームを作るのに必要な開発ツールは次の5つです。全て無償で入手できます。
Java 2 SDK, Standard Edition Version(JDK1.3)
パソコン上で動くJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。次に説明する「J2ME Wireless Toolkit」を実行するのに必要なので、それより先にインストールします。インストーラの指示に従ってインストールしてください。JDK1.4でない点に注意してください。
J2ME Wireless Toolkit 1.0.3(日本語版)
MIDP1.0仕様のJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。インストーラの指示に従ってインストールします。J2ME Wireless Toolkit 2.0でない点に注意してください。MIDPのAPIリファレンスはdocsディレクトリの中(C:\J2mewtk\docs\api)にあります。
J-SKY Application Emulator(P4型) Ver.2.0
Vアプリを作るための開発キットです。ボーダフォンのサイトで入手できます。インストーラの指示に従ってインストールしてください。同サイトには、などの開発に役立つドキュメントもあるので、いっしょに入手してください。
- Vアプリ開発ガイド[概要編]
- Vアプリ開発ガイド[開発編]
- APIリファレンス JavaDoc版
P5型開発用Stubclass
J-SKY Application Emulator(P4型)をP5型に対応させるための差分ファイルです。ボーダフォンのサイトで入手できます。ダウンロードと解凍を行うとP5_stubclassesディレクトリが出現するので、そのディレクトリ内にある全てのディレクトリ(comとjavaとjavax)をZIP圧縮して「stbclasses.zip」を生成します。それをJ-SKY Application Emulator(P4型)に含まれている同名ファイル「C:\J-PHONE-SDK\lib\stbclasses.zip(*1)」に上書きすればインストール完了です。
(*1)パスはJ-SKY Application Emulator(P4型)のインストール先によって変わります。
Voice Recognition Programming for Vodafone
Vアプリで音声認識を実装する時に役立つドキュメントです。「Mascot Capsule Toolkit for Vodafone」のサイトで入手できます。
執筆時現在(2003年12月)、P5型用の開発キットはリリースされていませんが、この記事を読む頃にはリリースしているかもしれません。その時は、「J-SKY Application Emulator(P4型)」と「P5型開発用Stubclass」の代りにP5型用の開発キットを使ってください。
| ★Vアプリ開発の基礎★ |
まずはじめに、「Hello World!」という文字列を表示するプログラムを作りながら、Vアプリ開発の基礎について説明します。今回のプログラムは、次の2つのクラスで構成されています。
- HelloWorldクラス ‐本体
- HelloCanvasクラス‐キャンバス
HelloWorldクラス
HelloWorldクラスは、プログラムの本体となるクラスです。プログラムファイルは前々回(JAVA PRESS Vol.32)と同じものなので説明は省略します。
HelloWorld.java import javax.microedition.lcdui.*; import javax.microedition.midlet.*; //HelloWorld(本体) public class HelloWorld extends MIDlet { //コンストラクタ public HelloWorld() { Display.getDisplay(this).setCurrent(new HelloCanvas()); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
HelloCanvasクラス
HelloCanvasクラスは、キャンバスとなるクラスです。こちらの説明も省略します。
HelloCanvas.java import javax.microedition.lcdui.*; //HelloWorld(キャンバス) public class HelloCanvas extends Canvas { //描画 public void paint(Graphics g) { g.setColor(255,255,255); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(0,0,0); g.drawString("Hello World!",0,0,g.LEFT|g.TOP); } }
コンパイルと検証
ソースコードの準備ができたら「javac」でコンパイルします。
javac -bootclasspath C:\J-PHONE-SDK\lib\stubclasses.zip -d . -g:none *.java
「-bootclasspath」にはJ-SKY Application Emulatorのlibディレクトリ内にある「stubclasses.zip」を指定します。「-g:none」はデバッグ情報を排除するオプションで、これによってクラスファイルのサイズを小さくしています。
次に「preverify」でクラスファイルを検証します。J2SEでは実行時にクラスが安全かどうかチェックしますが、処理能力が低い携帯端末ではかなりの負担になってしまいます。そこでJ2ME CLDCでは実行前に「preverify」によって検証を行い、実行時の負荷を減らしています。preverifyのコマンドは次の通りです。
C:\java\J2mewtk\bin\preverify -d . -classpath .;C:\J-PHONE-SDK\lib\stubclasses.zip HelloWorld
C:\java\J2mewtk\bin\preverify -d . -classpath .;C:\J-PHONE-SDK\lib\stubclasses.zip HelloCanvas
「preverify.exe」はJ2ME Wireless Toolkitのbinディレクトリにあります。「-classpath」にはカレントディレクトリと「stubclasses.zip」を指定します。「-d」で出力先をカレントディレクトリに設定しているので、検証前のクラスファイルに上書きされる形で、検証済みクラスファイルが出力されます。
JARファイルの作成
JARファイルはVアプリの実行ファイルで、をまとめたものです。
- 検証済みクラスファイル
- マニフェストファイル
- 画像ファイルや音声ファイル(使用する時)
マニフェストファイルは、JARファイルの属性情報(アプリ名やバージョン等)を記述したテキストファイルで、必須属性は次の6つです。
マニフェストファイルの必須属性 MIDlet-Name:名前(UTF-8、16バイト以下)
MIDlet-Vendor:ベンダ名(UTF-8、16バイト以下)
MIDlet-Version:バージョン(16バイト以下)
MIDlet-1:アプリ名,アイコンファイル名,クラス名(UTF-8、70バイト以下)
MicroEdition-Profile:プロファイル名
MicroEdition-Configuration:コンフィギュレーション名
今回のプログラムのマニフェストファイルは次のようになります。
MANIFEST.MF MIDlet-Name: HelloWorld
MIDlet-Vendor: NPAKA
MIDlet-Version: 1.0
MIDlet-1: HelloWorld, ,HelloWorld
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0
検証済みクラスファイルとマニフェストファイルをまとめてJARファイルを生成するコマンドの書式は次の通りです。
jar cmf <マニフェストファイル名> <JARファイル名> <JARに含めるファイル名1> <JARに含めるファイル名2> …
今回は、マニフェストファイル名「MANIFEST.MF」、JARファイル名「HelloWorld」、JARに含めるファイル名「HelloWorld.class」「HelloCanvas.class」を指定するので、次のようになります。
jar cmf MANIFEST.MF HelloWorld.jar HelloWorld.class HelloCanvas.class
JADファイルの作成
JADファイルはマニフェストファイルと同様に、JARファイルの属性情報を記述したテキストファイルで、JARファイルとは別ファイルとして存在します。携帯端末はJARファイルをダウンロードする時、先にJADファイルを読み込み、実行可能かどうかチェックしてから、JARファイルにアクセスしています。
必須属性は次の5つです。
JADファイルの必須属性 MIDlet-Name:名前(UTF-8、16バイト以下)
MIDlet-Vendor:ベンダ名(UTF-8、16バイト以下)
MIDlet-Version:バージョン(16バイト以下)
MIDlet-Jar-Size: JARファイルのサイズ
MIDlet-Jar-URL: JARファイル名(5バイト以上24バイト以下)
今回のプログラムのJADファイルは次のようになります。
HelloWorld.jad MIDlet-Name: HelloWorld
MIDlet-Vendor: NPAKA
MIDlet-Version: 1.0
MIDlet-Jar-Size: 1290
MIDlet-Jar-URL: HelloWorld.jar
MIDlet-Jar-Sizeの更新
MIDlet-Jar-Sizeの値はプログラムを変更すると変わり、そのたびにJADファイルを書き換えるのはとても面倒です。そこで、JARファイルのサイズをJADファイルのMIDlet-Jar-Sizeに書き込むJ2SEのプログラムを作りました。
SizeUpdate.java import java.io.*; import java.util.*; //MIDlet-Jar-Sizeを更新するプログラム public final class SizeUpdate { //更新 public void update(String name) { File file; List list; String str; //名前補正 if (name.endsWith(".jad")) { name=name.substring(0,name.length()-4); } //JADファイルチェック file=new File(name+".jad"); if(!file.exists()) { System.out.println(file.toString()+"が見つかりません。"); return; } //JARファイルチェック file=new File(name+".jar"); if(!file.exists()) { System.out.println(file.toString()+"が見つかりません。"); return; } try { //更新 list=readFile(name+".jad"); for(int i=0;i<list.size();i++) { str=(String)list.get(i); if(str.startsWith("MIDlet-Jar-Size:")) { list.set(i,"MIDlet-Jar-Size: "+file.length()); } } writeFile(name+".jad",list); System.out.println(name+".jadのサイズを更新しました。["+ file.length()+"byte]"); } catch(IOException e) { e.printStackTrace(); } } //ファイルの読み込み private List readFile(String name) throws IOException { ArrayList list=new ArrayList(); FileInputStream in =null; BufferedReader br =null; try { in=new FileInputStream(name); br=new BufferedReader(new InputStreamReader(in)); for(String str=br.readLine();str!= null;str=br.readLine()) { list.add(str); } br.close(); in.close(); } catch (Exception e) { try { if(br!=null) br.close(); if(in!=null) in.close(); } catch(IOException e2) { } } return list; } //ファイルの書き込み private void writeFile(String name,List list) throws IOException { FileOutputStream out=null; PrintWriter pw =null; try { out=new FileOutputStream(name); pw =new PrintWriter(out); for(int i=0;i<list.size();i++) { pw.print((String)list.get(i)+"\n"); } pw.flush(); pw.close(); out.close(); } catch (Exception e) { if(pw != null) pw.close(); if(out!= null) out.close(); } } //メイン public static void main(String args[]) { if(args.length<1) { System.out.println("java SizeUpdate JADファイル名"); System.exit(-1); } SizeUpdate sizeupdate=new SizeUpdate(); sizeupdate.update(args[0]); } }
コマンドの書式は、次の通りです。
java -classpath <SizeUpdate.classを置いたディレクトリ> SizeUpdate <JADファイル名>
C:\workディレクトリにSizeUpdate.classを置き、HelloWorld.jadのMIDlet-Jar-Sizeの値を更新するコマンドは、次の通りです。
java -classpath C:\work SizeUpdate HelloWorld.jad
ファイルサイズの制限
VアプリにもiアプリやEZアプリと同様に、ファイルサイズ制限があります。C4型は「JARファイル+JADファイル+データ保存領域」の合計が50Kバイト、P4型は100Kバイト、P5型は256Kバイトまで使えます。
型 ファイル種別 ファイルサイズ 合計サイズ C4型 JADファイル
JARファイル
データ保存領域3Kバイト
50Kバイト
50Kバイト50Kバイト P4型 JADファイル
JARファイル
データ保存領域3Kバイト
80Kバイト
50Kバイト100Kバイト P5型 JADファイル
JARファイル
データ保存領域3Kバイト
200Kバイト
200Kバイト256Kバイト
| ★音声認識を使ってみる★ |
次に、音声認識を使ったプログラム「VoiceRecogEx」を作ります。画面に"選択キーで開始!!"と表示されている時に選択キーを押すと、"音声認識を開始"と表示されるので電話に向かって話し掛けてください。のうち、どの言葉に一番近いかを「認識スコア」として表示されます。認識スコアが10以下の時はその言葉を発音した可能性が低く、1位の認識スコアが200以上で2位との差が100以上の時は発音した可能性が高いです。
- オハヨウ
- コンニチワ
- コンバンワ
今回のプログラムは、以下の2つのクラスで構成されています。
- VoiceRecogExクラス ‐本体
- VoiceRecogCanvasクラス‐キャンバス
VoiceRecogExクラス
VoiceRecogExクラスは、プログラムの本体となるクラスです。
VoiceRecogEx.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; //音声認識を使ってみる(本体) public class VoiceRecogEx extends MIDlet { //コンストラクタ public VoiceRecogEx() { Display.getDisplay(this).setCurrent(new VoiceRecogCanvas()); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
VoiceRecogCanvasクラス
VoiceRecogCanvasクラスは、キャンバスとなるクラスです。画面にはString型配列infoに含まれる文字列を表示します。
VoiceRecogCanvas.java import com.j_phone.io.*; import javax.microedition.lcdui.*; //音声認識を使ってみる(キャンバス) class VoiceRecogCanvas extends Canvas implements VoiceRecognitionListener { private final static String DICT_WORD[]={ //単語定数 null,"オハヨウ","コンニチワ","コンバンワ"}; private VoiceRecognitionDictionary dict; //辞書 private VoiceRecognition recog; //音声認識 private String[] info={"選択キーで開始!!"};//情報 //キープレスイベント public void keyPressed(int keyCode) { int action=getGameAction(keyCode); //音声認識を開始 if (action==FIRE) { try { //情報の表示 info=new String[]{"音声認識を開始"}; repaint(); //辞書の生成 dict=new VoiceRecognitionDictionary(); for (int i=1;i<DICT_WORD.length;i++) { dict.setWord(i,DICT_WORD[i]); } //音声認識を開始 recog=VoiceRecognition.getInstance(); recog.setVoiceRecognitionListener(this); recog.recognize(dict,4000,4000,3); } catch (Exception e) { //エラーの表示 info=new String[]{"エラー", e.getClass().getName()}; repaint(); } } } //音声認識開始を通知 public void recognitionStarted() { //情報の表示 info=new String[]{"音声認識中…"}; repaint(); } //音声認識完了を通知 public void recognized(int num) { //情報の表示 info=new String[num]; for (int i=1;i<=num;i++) { info[i-1]=DICT_WORD[recog.getCandidateWord(i)]+ "["+recog.getCandidateScore(i)+"]"; } repaint(); } //音声認識失敗を通知 public void recognitionFailed(int reason) { //情報の表示 info=new String[]{"音声認識失敗"}; repaint(); } //描画 public void paint(Graphics g) { g.setColor(255,255,255); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(0,0,0); for (int i=0;i<info.length;i++) { g.drawString(info[i],0,i*15,g.LEFT|g.TOP); } } }
com.j_phone.ioパッケージ
音声認識を行うためのクラスは、com.j_phone.ioパッケージに含まれているので、importしてください。
VoiceRecogCanvas.javaの一部 import com.j_phone.io.*;
キーイベント
キーイベントは、方向キーや数字キーを押したり離したりする時に発生するイベントです。キーを押すと実機からkeyPressed()メソッドが呼ばれ、キーを離すとkeyReleased()メソッドが呼ばれます。
void keyPressed(int keyCode)
keyCode:キーコード
void keyReleased(int keyCode)
keyCode:キーコード
方向キーと決定キーは、キーコードをCanvasクラスのgetGameAction()メソッドに渡して得られる値「Game Action」によって、どのキーが押されたかを判断します。Canvasクラスで持っているGame Action定数は次の9つです。
ゲームA・ゲームB・ゲームC・ゲームDの4つのキー定数は、Vアプリでは利用しません。
Game Action定数 Canvas.UP 上キー Canvas.DOWN 下キー Canvas.LEFT 左キー Canvas.RIGHT 右キー Canvas.FIRE 決定キー Canvas.GAME_A ゲームA Canvas.GAME_B ゲームB Canvas.GAME_C ゲームC Canvas.GAME_D ゲームD
数字キーと記号キー(#キー・*キー)は、getGameAction()メソッドは通さず、直接キーコード定数と比較します。Canvasクラスで持っているキーコード定数は次の12個です。
キーコード定数 Canvas.KEY_NUM0 0キー Canvas.KEY_NUM1 1キー Canvas.KEY_NUM2 2キー Canvas.KEY_NUM3 3キー Canvas.KEY_NUM4 4キー Canvas.KEY_NUM5 5キー Canvas.KEY_NUM6 6キー Canvas.KEY_NUM7 7キー Canvas.KEY_NUM8 8キー Canvas.KEY_NUM9 9キー Canvas.KEY_POUND #キー Canvas.KEY_STAR *キー
今回は、選択キーを押した時に音声認識の開始処理を行うので、次のようになります。
VoiceRecogCanvas.javaの一部 public void keyPressed(int keyCode) { int action=getGameAction(keyCode); //音声認識を開始 if (action==FIRE) { <<音声認識の開始処理>> } }
辞書の生成
Vアプリの音声認識機能は、辞書として登録された単語の中から、どの単語に一番近いかを判断します。辞書を用意するには、VoiceRecognitionDictionaryクラスのオブジェクトを生成する必要があります。
VoiceRecogCanvas.javaの一部 private VoiceRecognitionDictionary dict;
VoiceRecogCanvas.javaの一部 dict=new VoiceRecognitionDictionary();
辞書に単語を追加するには、setWord()メソッドを使います。
単語番号は単語を識別するための番号で、既に同じ番号が設定されている時は上書きされます。設定可能な値は1から9999で、0からでない点に注意してください。追加する単語は半角カタカナで記述し、1単語20文字、100単語500文字まで可能です。
void setWord(int wordNo,String word)
wordNo:単語番号
word :単語
今回はString型配列DICT_WORDの値を追加するので、次のようになります。
VoiceRecogCanvas.javaの一部 private final static String DICT_WORD[]={ //単語定数 null,"オハヨウ","コンニチワ","コンバンワ"};
VoiceRecogCanvas.javaの一部 for (int i=1;i<DICT_WORD.length;i++) { dict.setWord(i,DICT_WORD[i]); }
音声認識を開始
辞書が用意できたら、音声認識を開始します。まず、音声認識の処理を行うVoiceRecognitionオブジェクトをVoiceRecognitionクラスのgetInstance()で取得してください。取得できたら、setVoiceRecognitionListener()メソッドで音声認識イベントの通知先を指定します。
今回は、VoiceRecogCanvasクラス自身が音声認識リスナーになるので、thisをセットします。
void setVoiceRecognitionListener(VoiceRecognitionListener listener)
listener:音声認識リスナー
VoiceRecogCanvas.javaの一部 private VoiceRecognition recog; //音声認識
VoiceRecogCanvas.javaの一部 recog=VoiceRecognition.getInstance();
recog.setVoiceRecognitionListener(this);
音声認識を開始するには、recognize()メソッドを使います。
void recognize(VoiceRecognitionDictionary dict,int voiceOffTimeOut,int voiceOnTimeOut,int maxCandidate)
dict:辞書
voiceOffTimeOut:音声入力がない時のタイムアウト時間(10〜10000ミリ秒)
voiceOnTimeOut:音声入力がある時のタイムアウト時間(10〜10000ミリ秒)
maxCandidate:認識結果の取得候補数(1〜20)
今回は音声がない時とある時のタイムアウト時間に4秒(4000ミリ秒)、認識結果の取得候補数に3を指定するので、次のようになります。
VoiceRecogCanvas.javaの一部 recog.recognize(dict,4000,4000,3);
音声認識リスナーの実装
音声認識リスナーは、音声認識のイベント情報を受信するためのリスナーです。今回は、VoiceRecogCanvasクラス自身にリスナーのインタフェースを実装します。
VoiceRecogCanvas.javaの一部 class VoiceRecogCanvas extends Canvas implements VoiceRecognitionListener {
音声認識リスナーには、次の3つのメソッドが必要です。
- void recognitionStarted()
- void recognized(int num)
- void recognitionFailed(int reason)
void recognitionStarted()
音声認識を開始した時に呼ばれるメソッドです。今回は、"音声認識中…"という文字列を表示しています。
VoiceRecogCanvas.javaの一部 public void recognitionStarted() { //情報の表示 info=new String[]{"音声認識中…"}; repaint(); }
void recognized(int num)
音声認識が成功した時に呼ばれるメソッドです。引数numには認識した単語の数が渡されます。認識結果から指定の順位の語句番号を取得するには、getCandidateWord()メソッドを使います。
int getCandidateWord(int order)
order:語句番号
認識結果から指定の順位の認識スコアを取得するには、getCandidateScore()メソッドを使います。
int getCandidateScore(int order)
order:語句番号
今回は、辞書に登録されている言葉のうち、発音が近いと認識した順に3つを、認識スコアといっしょに表示しています。
VoiceRecogCanvas.javaの一部 public void recognized(int num) { //情報の表示 info=new String[num]; for (int i=1;i<=num;i++) { info[i-1]=DICT_WORD[recog.getCandidateWord(i)]+ "["+recog.getCandidateScore(i)+"]"; } repaint(); }
void recognitionFailed(int reason)
音声認識を失敗した時に呼ばれるメソッドです。引数reasonには失敗理由を示す数値が渡されます。
1:無声時間タイムアウト
2:音声入力タイムアウト
3:その他のエラー
4:音声認識の開始失敗
今回は、"音声認識失敗"と表示しています。
VoiceRecogCanvas.javaの一部 public void recognitionFailed(int reason) { //情報の表示 info=new String[]{"音声認識失敗"}; repaint(); }
マニフェストファイルとJADファイル
VアプリでJSCL1.2の機能を使った時は、マニフェストファイルとJADファイルに「MIDlet-OCL: JSCL-1.2.0」の1行を追加する必要があります。
MANIFEST.MF MIDlet-Name: VoiceRecogEx
MIDlet-Vendor: NPAKA
MIDlet-Version: 1.0
MIDlet-OCL: JSCL-1.2.0
MIDlet-1: VoiceRecogEx,,VoiceRecogEx
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0
VoiceRecogEx.jad MIDlet-Name: VoiceRecogEx
MIDlet-Vendor: NPAKA
MIDlet-Version: 1.0
MIDlet-OCL: JSCL-1.2.0
MIDlet-Jar-Size: 2277
MIDlet-Jar-URL: VoiceRecogEx.jar
エミュレータでの実行
2003年12月現在、P5型用の開発ツールは一般公開されていますが、エミュレータは提供されていません。そのため、実機で直接動作テストする必要があります。
| ★こたえて!そらみを作る★ |
それでは、本題の音声認識アプリ「こたえて!そらみ」を作ります。アプリを起動すると画面にそらみが現れます。決定キーを押すとそらみが「なに?」と聞いてくるので、話し掛けてあげてください。その言葉に応じて、そらみが返答してくれます。
言葉 返答 オハヨウ おっはー! コンニチワ こんちわ〜 コンバンワ こんばんわぁ!
今回のプログラムは、次の2つのクラスで構成されています。
- KotaSoraクラス ‐本体
- KotaCanvasクラス‐キャンバス
画像ファイルの用意
Vアプリで利用できる画像ファイル形式は256色以下のインデックスカラーPNG(PNG-8)とJPEGです。今回は次の3枚のPNGファイルを使います。JARファイルに含めてください。
・そらみ(待ち状態)
-0.png
-240x260
・そらみ(聞き状態)
-1.png
-240x260
・そらみ(会話状態)
-2.png
-240x260
サウンドファイルの用意
Vアプリで利用できるサウンドファイルは、SMD(*.smd,*.smz,*.smx)、SMAF/MA2(*.mmf)、SMAF/MA3(*.mmf)、SMF/Phrase(*.spf)です。今回は次の4つのサウンドファイルを使います。JARファイルに含めてください。
・なに?
-0.mmf
・おっはー!
-1.mmf
・こんちわ〜
-2.mmf
・こんばんわぁ!
-3.mmf
KotaSoraクラス
KotaSoraクラスは、プログラムの本体となるクラスです。
KotaSora.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; //こたえて!そらみ(本体) public class KotaSora extends MIDlet { //コンストラクタ public KotaSora() { Display.getDisplay(this).setCurrent(new KotaCanvas()); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
KotaCanvasクラス
KotaCanvasクラスは、キャンバスとなるクラスです。
KotaCanvas.java import com.jblend.media.smaf.*; import com.jblend.media.*; import com.j_phone.io.*; import javax.microedition.lcdui.*; //こたえて!そらみ(キャンバス) class KotaCanvas extends Canvas implements VoiceRecognitionListener,MediaPlayerListener { private final static String DICT_WORD[]={ //単語定数 null,"オハヨウ","コンニチワ","コンバンワ"}; private VoiceRecognitionDictionary dict; //辞書 private VoiceRecognition recog; //音声認識 private final static int S_WAIT=0,S_HEAR=1,S_TALK=2;//状態定数 private int state =S_WAIT; //状態 private Image[] image =new Image[3]; //イメージ private SmafPlayer player=new SmafPlayer();//プレイヤー private SmafData[] sound =new SmafData[4]; //サウンド //コンストラクタ KotaCanvas() { try { //イメージの読み込み for (int i=0;i<3;i++) { image[i]=Image.createImage("/"+i+".png"); } //サウンドの読み込み for (int i=0;i<4;i++) { sound[i]=new SmafData("resource:"+i+".mmf"); } } catch (Exception e) { } } //描画 public void paint(Graphics g) { if (image[state]!=null) { g.drawImage(image[state],0,0,g.LEFT|g.TOP); } } //キープレスイベント public void keyPressed(int keyCode) { int action=getGameAction(keyCode); //聞き状態へ if (state==S_WAIT && action==FIRE) { try { //サウンドの再生 player.setData(sound[0]); player.play(); player.addMediaPlayerListener(this); } catch (Exception e) { } } } //プレイヤーの状態変化を通知 public void playerStateChanged(MediaPlayer player) { //聞き状態へ if (state==S_WAIT) { try { //辞書の生成 dict=new VoiceRecognitionDictionary(); for (int i=1;i<DICT_WORD.length;i++) { dict.setWord(i,DICT_WORD[i]); } //音声認識を開始 recog=VoiceRecognition.getInstance(); recog.setVoiceRecognitionListener(this); recog.recognize(dict,4000,4000,3); //状態の表示 state=S_HEAR; repaint(); } catch (Exception e) { } } //待ち状態へ else { //状態の表示 state=S_WAIT; repaint(); } //メディアプレイヤーリスナーの解除 player.removeMediaPlayerListener(this); } //プレイヤーの繰り返し再生を通知 public void playerRepeated(MediaPlayer player) { } //音声認識開始を通知 public void recognitionStarted() { } //音声認識完了を通知 public void recognized(int num) { try { if (num>=1 && recog.getCandidateScore(1)>=150) { //サウンドの再生 player.setData(sound[recog.getCandidateWord(1)]); player.play(); player.addMediaPlayerListener(this); //状態の表示 state=S_TALK; repaint(); } else { //状態の表示 state=S_WAIT; repaint(); } } catch (Exception e) { } } //音声認識失敗を通知 public void recognitionFailed(int reason) { //状態の表示 state=S_WAIT; repaint(); } }
com.jblend.media.smafパッケージとcom.jblend.mediaパッケージ
サウンドの再生を行うためのクラスは、com.jblend.media.smafパッケージとcom.jblend.mediaパッケージに含まれているので、importしてください。
KotaCanvas.javaの一部 import com.jblend.media.smaf.*;
import com.jblend.media.*;
状態の遷移
今回のアプリには、次の2つの状態があります。現在の状態はint型変数stateで保持しています。
- 待ち状態(S_WAIT)
何もしていない状態です。決定キーを押した時、聞き状態に遷移します。- 聞き状態(S_HEAR)
音声認識を開始した状態です。そらみが「なに?」と言った後、4秒以内に話し掛けてください。話し掛けた時は会話状態に、タイムアウトした時は待ち状態に遷移します。- 会話状態(S_TALK)
そらみが返答している状態です。返答後、待ち状態に遷移します。
KotaCanvas.javaの一部 private final static int S_WAIT=0,S_HEAR=1,S_TALK=2;//状態定数
KotaCanvas.javaの一部 private int state =S_WAIT; //状態
イメージの読み込みと描画
ImageクラスのcreateImage()メソッドで画像ファイルを読み込みます。ファイル名には「/0.gif」のように頭に"/"をつけてください。
KotaCanvas.javaの一部 for (int i=0;i<3;i++) { image[i]=Image.createImage("/"+i+".png"); }
GraphicsクラスのdrawImage()メソッドでイメージをキャンバスに描画します。
void drawImage(Image image,int x,int y,int align)
image:表示するイメージ
x :X座標
y :Y座標
align:配置
align引数には配置定数を指定します。指定した座標に文字列の左上を配置したい時は"Graphics.LEFT|Graphics.UP"を指定します。
配置定数 Graphics.TOP 上 Graphics.BOTTOM 下 Graphics.LEFT 左 Graphics.RIGHT 右 Graphics.HCENTER 水平中央 Graphics.VCENTER 垂直中央
今回は、state変数に対応したイメージを表示するので、次のようになります。
KotaCanvas.javaの一部 if (image[state]!=null) { g.drawImage(image[state],0,0,g.LEFT|g.TOP); }
サウンドの読み込みと再生
SMAFファイルを読み込むには、SmafDataクラスを使います。コンストラクタは次の通りです。読み込み先を次のフォーマットで指定します。
SmafData(String location)
location:読み込み先
resource:ファイル名
今回は、0.mmf〜3.mmfを読み込むので次のようになります。
KotaCanvas.javaの一部 for (int i=0;i<4;i++) { sound[i]=new SmafData("resource:"+i+".mmf"); }
サウンドを鳴らすのにはSmafPlayerクラスを使います。SmafPlayerクラスのオブジェクトを生成し、setData()メソッドでSmafDataオブジェクトをセットし、play()メソッドで再生、stop()メソッドで停止します。
void setData(SmafData data)
data:SmafDataオブジェクト
今回は、音声認識完了を通知された時、認識スコアが150以上の時に、対応するサウンドを再生するので、次のようになります。
KotaCanvas.javaの一部 try { if (num>=1 && recog.getCandidateScore(1)>=150) { //サウンドの再生 player.setData(sound[recog.getCandidateWord(1)]); player.play(); player.addMediaPlayerListener(this); //状態の表示 state=S_TALK; repaint(); } else { //状態の表示 state=S_WAIT; repaint(); } } catch (Exception e) { }
マニフェストファイルとJADファイル
QVGA端末(画面解像度の大きな端末)では、昔の小さな画面解像度向けに作られたアプリに対応するために、縦横2倍で拡大表示されます。240x260ドットの高解像度なアプリを作りたい時は、マニフェストファイルとJADファイルに「MIDlet-Application-Range: 0,0」の1行を追加する必要があります。
J-SH53の画面サイズとフォントサイズ 画面サイズ フォントLARGE フォントMEDIUM フォントSMALL 通常モード 120x130 20x19 12x12 12x12 高詳細モード 240x260 20x19 20x19 12x12
また、マニフェストファイルやJADファイルで日本語を使った時は、UTF-8エンコードで保存するようにしてください。UTF-8では全角1文字が2バイトとは限らないので、文字列サイズの制限に注意してください。
MANIFEST.MF MIDlet-Name: こたえて!そらみ
MIDlet-Vendor: NPAKA
MIDlet-Version: 1.0
MIDlet-OCL: JSCL-1.2.0
MIDlet-Application-Range: 0,0
MIDlet-1: KotaSora,,KotaSora
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0
KotaSora.jad MIDlet-Name: こたえて!そらみ
MIDlet-Vendor: NPAKA
MIDlet-Version: 1.0
MIDlet-OCL: JSCL-1.2.0
MIDlet-Application-Range: 0,0
MIDlet-Jar-Size: 84401
MIDlet-Jar-URL: KotaSora.jar
| ★おわりに★ |
次回は、パケ代定額で話題沸騰のEV-DO端末で動くEZアプリを作る予定です。お楽しみに。
−戻る−
(C)Npaka/Sehira, 2003-2004