work in progress on TTS, needs more changes

This commit is contained in:
Pavol Zibrita 2011-06-05 23:37:01 +02:00
parent 932e0dc96b
commit 45002d3a77
14 changed files with 815 additions and 443 deletions

View file

@ -49,6 +49,7 @@
<intent-filter><action android:name="net.osmand.plus.NavigationService"></action></intent-filter>
</service>
<receiver android:name=".OnNavigationServiceAlarmReceiver"/>
<activity android:name=".activities.InitTTSActivity"></activity>
</application>

View file

@ -0,0 +1,67 @@
package net.osmand.plus.activities;
import java.util.Locale;
import net.osmand.LogUtil;
import net.osmand.plus.voice.TTSOsmand;
import org.apache.commons.logging.Log;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
public class InitTTSActivity extends Activity implements OnInitListener {
private static final Log log = LogUtil
.getLog(InitTTSActivity.class);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTts = new TextToSpeech(this, this);
final int languageAvailable = mTts.isLanguageAvailable(Locale.FRANCE);
log.info("Language availbility:" + languageAvailable);
}
private TextToSpeech mTts;
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
// success, create the TTS instance
int result = mTts.setLanguage(Locale.US);
TTSOsmand.mTts = mTts;
// Try this someday for some interesting results.
// int result mTts.setLanguage(Locale.FRANCE);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
//TODO
}
} else {
// missing data, install it
if (mTts != null) {
mTts.speak("Needs to install data!", TextToSpeech.QUEUE_ADD, null);
Intent installIntent = new Intent();
installIntent
.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
} else {
log.info("onInit called again with status: " + status);
}
}
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mTts != null) {
mTts.shutdown();
mTts = null;
}
}
}

View file

@ -24,10 +24,12 @@ import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.plus.voice.CommandPlayerException;
import net.osmand.plus.voice.CommandPlayerFactory;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Application;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -211,30 +213,35 @@ public class OsmandApplication extends Application {
}
private void initVoiceDataInDifferentThread(Context uiContext) {
final ProgressDialog dlg = ProgressDialog.show(uiContext, getString(R.string.loading_data), getString(R.string.voice_data_initializing));
private void initVoiceDataInDifferentThread(final Context uiContext) {
// final ProgressDialog dlg = ProgressDialog.show(uiContext,
// getString(R.string.loading_data),
// getString(R.string.voice_data_initializing));
new Thread(new Runnable() {
@Override
public void run() {
String w = null;
try {
w = initCommandPlayer();
} finally {
dlg.dismiss();
}
if(w != null){
showWarning(dlg.getContext(), w);
initCommandPlayer();
// dlg.dismiss();
} catch (CommandPlayerException e) {
// dlg.dismiss();
showWarning(uiContext, e.getError());
}
}
}).start();
}
public String initCommandPlayer() {
if (player == null) {
player = new CommandPlayer(OsmandApplication.this);
public void initCommandPlayer()
throws CommandPlayerException
{
final String voiceProvider = osmandSettings.VOICE_PROVIDER.get();
if (player == null || !Algoritms.objectEquals(voiceProvider, player.getCurrentVoice())) {
if (player != null) {
player.clear();
}
player = CommandPlayerFactory.createCommandPlayer(voiceProvider,OsmandApplication.this, getApplicationContext());
routingHelper.getVoiceRouter().setPlayer(player);
}
return player.init(osmandSettings.VOICE_PROVIDER.get());
}
public NavigationService getNavigationService() {

View file

@ -396,7 +396,8 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
values[ki] = MORE_VALUE;
fill(tileSourcePreference, entries, values, value);
}
private void fill(ListPreference component, String[] list, String[] values, String selected) {
component.setEntries(list);
component.setEntryValues(values);
@ -435,7 +436,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
// Specific actions after list preference changed
if (changed) {
if (listPref.getId().equals(osmandSettings.VOICE_PROVIDER.getId())) {
getMyApplication().initCommandPlayer();
getMyApplication().showDialogInitializingCommandPlayer(this);
} else if (listPref.getId().equals(osmandSettings.APPLICATION_MODE.getId())) {
updateAllSettings();
} else if (listPref.getId().equals(osmandSettings.PREFERRED_LOCALE.getId())) {

View file

@ -2,8 +2,9 @@ package net.osmand.plus.activities;
import net.osmand.plus.activities.RoutingHelper.RouteDirectionInfo;
import net.osmand.plus.activities.RoutingHelper.TurnType;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.plus.voice.CommandPlayer.CommandBuilder;
public class VoiceRouter {
@ -227,17 +228,17 @@ public class VoiceRouter {
private String getTurnType(TurnType t){
if(TurnType.TL.equals(t.getValue())){
return CommandPlayer.A_LEFT;
return AbstractPrologCommandPlayer.A_LEFT;
} else if(TurnType.TSHL.equals(t.getValue())){
return CommandPlayer.A_LEFT_SH;
return AbstractPrologCommandPlayer.A_LEFT_SH;
} else if(TurnType.TSLL.equals(t.getValue())){
return CommandPlayer.A_LEFT_SL;
return AbstractPrologCommandPlayer.A_LEFT_SL;
} else if(TurnType.TR.equals(t.getValue())){
return CommandPlayer.A_RIGHT;
return AbstractPrologCommandPlayer.A_RIGHT;
} else if(TurnType.TSHR.equals(t.getValue())){
return CommandPlayer.A_RIGHT_SH;
return AbstractPrologCommandPlayer.A_RIGHT_SH;
} else if(TurnType.TSLR.equals(t.getValue())){
return CommandPlayer.A_RIGHT_SL;
return AbstractPrologCommandPlayer.A_RIGHT_SL;
}
return null;
}

View file

@ -0,0 +1,179 @@
package net.osmand.plus.voice;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.osmand.LogUtil;
import net.osmand.data.IndexConstants;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import org.apache.commons.logging.Log;
import alice.tuprolog.InvalidLibraryException;
import alice.tuprolog.InvalidTheoryException;
import alice.tuprolog.NoSolutionException;
import alice.tuprolog.Number;
import alice.tuprolog.Prolog;
import alice.tuprolog.SolveInfo;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import alice.tuprolog.Theory;
import alice.tuprolog.Var;
import android.content.Context;
public abstract class AbstractPrologCommandPlayer implements CommandPlayer {
private static final Log log = LogUtil
.getLog(AbstractPrologCommandPlayer.class);
protected Context ctx;
protected File voiceDir;
protected Prolog prologSystem;
protected static final String P_VERSION = "version";
protected static final String P_RESOLVE = "resolve";
public static final String A_LEFT = "left";
public static final String A_LEFT_SH = "left_sh";
public static final String A_LEFT_SL = "left_sl";
public static final String A_RIGHT = "right";
public static final String A_RIGHT_SH = "right_sh";
public static final String A_RIGHT_SL = "right_sl";
protected static final String DELAY_CONST = "delay_";
protected AbstractPrologCommandPlayer(Context ctx, String voiceProvider, String configFile)
throws CommandPlayerException
{
long time = System.currentTimeMillis();
try {
this.ctx = ctx;
prologSystem = new Prolog(
new String[] { "alice.tuprolog.lib.BasicLibrary" }); //$NON-NLS-1$
} catch (InvalidLibraryException e) {
log.error("Initializing error", e); //$NON-NLS-1$
throw new RuntimeException(e);
}
if (log.isInfoEnabled()) {
log.info("Initializing prolog system : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
}
init(voiceProvider, configFile);
}
private void init(String voiceProvider, String configFile) throws CommandPlayerException {
prologSystem.clearTheory();
voiceDir = null;
if (voiceProvider != null) {
File parent = OsmandSettings.getOsmandSettings(ctx).extendOsmandPath(ResourceManager.VOICE_PATH);
voiceDir = new File(parent, voiceProvider);
if (!voiceDir.exists()) {
voiceDir = null;
throw new CommandPlayerException(
ctx.getString(R.string.voice_data_unavailable));
}
}
// see comments below why it is impossible to read from zip (don't know
// how to play file from zip)
// voiceZipFile = null;
if (voiceDir != null) {
long time = System.currentTimeMillis();
boolean wrong = false;
try {
InputStream config;
// if (voiceDir.getName().endsWith(".zip")) { //$NON-NLS-1$
// voiceZipFile = new ZipFile(voiceDir);
// config = voiceZipFile.getInputStream(voiceZipFile.getEntry("_config.p")); //$NON-NLS-1$
// } else {
config = new FileInputStream(new File(voiceDir, configFile)); //$NON-NLS-1$
// }
if (!wrong) {
prologSystem.setTheory(new Theory(config));
}
} catch (InvalidTheoryException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
} catch (IOException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
}
if (wrong) {
throw new CommandPlayerException(
ctx.getString(R.string.voice_data_corrupted));
} else {
boolean versionSupported = false;
Var v = new Var("VERSION"); //$NON-NLS-1$
SolveInfo s = prologSystem.solve(new Struct(P_VERSION, v));
if (s.isSuccess()) {
prologSystem.solveEnd();
try {
Term val = s.getVarValue(v.getName());
if (val instanceof Number) {
versionSupported = ((Number) val).intValue() == IndexConstants.VOICE_VERSION;
}
} catch (NoSolutionException e) {
}
}
if (!versionSupported) {
throw new CommandPlayerException(
ctx.getString(R.string.voice_data_not_supported));
}
}
if (log.isInfoEnabled()) {
log.info("Initializing voice subsystem " + voiceProvider + " : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
@Override
public List<String> execute(List<Struct> listCmd){
Struct list = new Struct(listCmd.toArray(new Term[listCmd.size()]));
Var result = new Var("RESULT"); //$NON-NLS-1$
List<String> files = new ArrayList<String>();
SolveInfo res = prologSystem.solve(new Struct(P_RESOLVE, list, result));
if (res.isSuccess()) {
try {
prologSystem.solveEnd();
Term solution = res.getVarValue(result.getName());
Iterator<?> listIterator = ((Struct) solution).listIterator();
while(listIterator.hasNext()){
Object term = listIterator.next();
if(term instanceof Struct){
files.add(((Struct) term).getName());
}
}
} catch (NoSolutionException e) {
}
}
return files;
}
@Override
public String getCurrentVoice() {
if (voiceDir == null) {
return null;
}
return voiceDir.getName();
}
@Override
public CommandBuilder newCommandBuilder() {
return new CommandBuilder(this);
}
@Override
public void clear() {
ctx = null;
prologSystem = null;
}
}

View file

@ -0,0 +1,179 @@
package net.osmand.plus.voice;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.osmand.LogUtil;
import org.apache.commons.logging.Log;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
public class CommandBuilder {
private static final Log log = LogUtil.getLog(CommandBuilder.class);
protected static final String C_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
protected static final String C_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
protected static final String C_PREPARE_MAKE_UT = "prepare_make_ut"; //$NON-NLS-1$
protected static final String C_ROUNDABOUT = "roundabout"; //$NON-NLS-1$
protected static final String C_GO_AHEAD = "go_ahead"; //$NON-NLS-1$
protected static final String C_TURN = "turn"; //$NON-NLS-1$
protected static final String C_MAKE_UT = "make_ut"; //$NON-NLS-1$
protected static final String C_PREAMBLE = "preamble"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_DESTINATION = "and_arrive_destination"; //$NON-NLS-1$
protected static final String C_THEN = "then"; //$NON-NLS-1$
protected static final String C_REACHED_DESTINATION = "reached_destination"; //$NON-NLS-1$
protected static final String C_BEAR_LEFT = "bear_left"; //$NON-NLS-1$
protected static final String C_BEAR_RIGHT = "bear_right"; //$NON-NLS-1$
protected static final String C_ROUTE_RECALC = "route_recalc"; //$NON-NLS-1$
protected static final String C_ROUTE_NEW_CALC = "route_new_calc"; //$NON-NLS-1$
/**
*
*/
private final CommandPlayer commandPlayer;
private boolean alreadyExecuted = false;
private List<Struct> listStruct = new ArrayList<Struct>();
public CommandBuilder(CommandPlayer commandPlayer){
this(commandPlayer, true);
}
public CommandBuilder(CommandPlayer commandPlayer, boolean preamble) {
this.commandPlayer = commandPlayer;
if (preamble) {
addCommand(C_PREAMBLE);
}
}
private void checkState(){
if(alreadyExecuted){
throw new IllegalArgumentException();
}
}
private CommandBuilder addCommand(String name, Object... args){
checkState();
Term[] list = new Term[args.length];
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if(o instanceof java.lang.Number){
if(o instanceof java.lang.Double){
list[i] = new alice.tuprolog.Double((Double) o);
} else if(o instanceof java.lang.Float){
list[i] = new alice.tuprolog.Float((Float) o);
} else if(o instanceof java.lang.Long){
list[i] = new alice.tuprolog.Long((Long) o);
} else {
list[i] = new alice.tuprolog.Int(((java.lang.Number)o).intValue());
}
} else if(o instanceof String){
list[i] = new Struct((String) o);
}
if(list[i]== null){
throw new NullPointerException(name +" " + o); //$NON-NLS-1$
}
}
Struct struct = new Struct(name, list);
if(log.isDebugEnabled()){
log.debug("Adding command : " + name + " " + Arrays.toString(args)); //$NON-NLS-1$ //$NON-NLS-2$
}
listStruct.add(struct);
return this;
}
public CommandBuilder goAhead(){
return addCommand(C_GO_AHEAD);
}
public CommandBuilder goAhead(double dist){
return addCommand(C_GO_AHEAD, dist);
}
public CommandBuilder makeUT(){
return addCommand(C_MAKE_UT);
}
public CommandBuilder makeUT(double dist){
return addCommand(C_MAKE_UT, dist);
}
public CommandBuilder prepareMakeUT(double dist){
return addCommand(C_PREPARE_MAKE_UT, dist);
}
public CommandBuilder turn(String param){
return addCommand(C_TURN, param);
}
public CommandBuilder turn(String param, double dist){
return addCommand(C_TURN, param, dist);
}
/**
*
* @param param A_LEFT, A_RIGHT, ...
* @param dist
* @return
*/
public CommandBuilder prepareTurn(String param, double dist){
return addCommand(C_PREPARE_TURN, param, dist);
}
public CommandBuilder prepareRoundAbout(double dist){
return addCommand(C_PREPARE_ROUNDABOUT, dist);
}
public CommandBuilder roundAbout(double dist, double angle, int exit){
return addCommand(C_ROUNDABOUT, dist, angle, exit);
}
public CommandBuilder roundAbout(double angle, int exit){
return addCommand(C_ROUNDABOUT, angle, exit);
}
public CommandBuilder andArriveAtDestination(){
return addCommand(C_AND_ARRIVE_DESTINATION);
}
public CommandBuilder arrivedAtDestination(){
return addCommand(C_REACHED_DESTINATION);
}
public CommandBuilder bearLeft(){
return addCommand(C_BEAR_LEFT);
}
public CommandBuilder bearRight(){
return addCommand(C_BEAR_RIGHT);
}
public CommandBuilder then(){
return addCommand(C_THEN);
}
public CommandBuilder newRouteCalculated(double dist){
return addCommand(C_ROUTE_NEW_CALC, dist);
}
public CommandBuilder routeRecalculated(double dist){
return addCommand(C_ROUTE_RECALC, dist);
}
public void play(){
this.commandPlayer.playCommands(this);
}
protected List<String> execute(){
alreadyExecuted = true;
return this.commandPlayer.execute(listStruct);
}
}

View file

@ -1,420 +1,19 @@
package net.osmand.plus.voice;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import net.osmand.LogUtil;
import net.osmand.data.IndexConstants;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import org.apache.commons.logging.Log;
import alice.tuprolog.InvalidLibraryException;
import alice.tuprolog.InvalidTheoryException;
import alice.tuprolog.NoSolutionException;
import alice.tuprolog.Number;
import alice.tuprolog.Prolog;
import alice.tuprolog.SolveInfo;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import alice.tuprolog.Theory;
import alice.tuprolog.Var;
import android.content.Context;
import android.media.MediaPlayer;
/**
* That class represents command player.
* It gets commands from input, analyze what files should be played and play
* them using media player
*/
public class CommandPlayer {
private static final Log log = LogUtil.getLog(CommandPlayer.class);
protected Context ctx;
// or zip file
private File voiceDir;
// private ZipFile voiceZipFile;
// resolving commands to play
private Prolog prologSystem;
// playing media
private MediaPlayer mediaPlayer;
// indicates that player is ready to play first file
private boolean playNext = true;
private List<String> filesToPlay = Collections.synchronizedList(new ArrayList<String>());
public CommandPlayer(Context ctx){
long time = System.currentTimeMillis();
try {
this.ctx = ctx;
prologSystem = new Prolog(new String[]{"alice.tuprolog.lib.BasicLibrary"}); //$NON-NLS-1$
} catch (InvalidLibraryException e) {
log.error("Initializing error", e); //$NON-NLS-1$
throw new RuntimeException(e);
}
mediaPlayer = new MediaPlayer();
if (log.isInfoEnabled()) {
log.info("Initializing prolog system : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
}
}
public String getCurrentVoice(){
if(voiceDir == null){
return null;
}
return voiceDir.getName();
}
public String init(String voiceProvider){
prologSystem.clearTheory();
voiceDir = null;
if(voiceProvider != null){
File parent = OsmandSettings.getOsmandSettings(ctx).extendOsmandPath(ResourceManager.VOICE_PATH);
voiceDir = new File(parent, voiceProvider);
if(!voiceDir.exists()){
voiceDir = null;
return ctx.getString(R.string.voice_data_unavailable);
}
}
// see comments below why it is impossible to read from zip (don't know how to play file from zip)
// voiceZipFile = null;
if(voiceDir != null) {
long time = System.currentTimeMillis();
boolean wrong = false;
try {
InputStream config;
// if (voiceDir.getName().endsWith(".zip")) { //$NON-NLS-1$
// voiceZipFile = new ZipFile(voiceDir);
// config = voiceZipFile.getInputStream(voiceZipFile.getEntry("_config.p")); //$NON-NLS-1$
// } else {
config = new FileInputStream(new File(voiceDir, "_config.p")); //$NON-NLS-1$
// }
if (!wrong) {
prologSystem.setTheory(new Theory(config));
}
} catch (InvalidTheoryException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
} catch (IOException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
}
if(wrong){
return ctx.getString(R.string.voice_data_corrupted);
} else {
boolean versionSupported = false;
Var v = new Var("VERSION"); //$NON-NLS-1$
SolveInfo s = prologSystem.solve(new Struct(P_VERSION, v));
if(s.isSuccess()){
prologSystem.solveEnd();
try {
Term val = s.getVarValue(v.getName());
if(val instanceof Number){
versionSupported = ((Number) val).intValue() == IndexConstants.VOICE_VERSION;
}
} catch (NoSolutionException e) {
}
}
if(!versionSupported){
return ctx.getString(R.string.voice_data_not_supported);
}
}
if (log.isInfoEnabled()) {
log.info("Initializing voice subsystem " + voiceProvider + " : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return null;
}
public CommandBuilder newCommandBuilder(){
return new CommandBuilder();
}
protected List<String> execute(List<Struct> listCmd){
Struct list = new Struct(listCmd.toArray(new Term[listCmd.size()]));
Var result = new Var("RESULT"); //$NON-NLS-1$
List<String> files = new ArrayList<String>();
SolveInfo res = prologSystem.solve(new Struct(P_RESOLVE, list, result));
if (res.isSuccess()) {
try {
prologSystem.solveEnd();
Term solution = res.getVarValue(result.getName());
Iterator<?> listIterator = ((Struct) solution).listIterator();
while(listIterator.hasNext()){
Object term = listIterator.next();
if(term instanceof Struct){
files.add(((Struct) term).getName());
}
}
} catch (NoSolutionException e) {
}
}
return files;
}
public void playCommands(CommandBuilder builder){
filesToPlay.addAll(builder.execute());
playQueue();
}
private synchronized void playQueue() {
while (!filesToPlay.isEmpty() && playNext) {
String f = filesToPlay.remove(0);
if (f != null && voiceDir != null) {
boolean exists = false;
// if(voiceZipFile != null){
// ZipEntry entry = voiceZipFile.getEntry(f);
// exists = entry != null;
// voiceZipFile.getInputStream(entry);
//
// } else {
File file = new File(voiceDir, f);
exists = file.exists();
// }
if (exists) {
log.debug("Playing file : " + f); //$NON-NLS-1$
playNext = false;
try {
// Can't play sound file from zip it seams to be impossible only unpack and play!!!
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mediaPlayer = new MediaPlayer();
int sleep = 60;
boolean delay = true;
while (!filesToPlay.isEmpty() && delay) {
delay = filesToPlay.get(0).startsWith(DELAY_CONST);
if (delay) {
String s = filesToPlay.remove(0).substring(DELAY_CONST.length());
try {
sleep += Integer.parseInt(s);
} catch (NumberFormatException e) {
}
}
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
playNext = true;
playQueue();
}
});
mediaPlayer.start();
} catch (Exception e) {
log.error("Error while playing voice command", e); //$NON-NLS-1$
playNext = true;
}
} else {
log.info("Play file not found : " + f); //$NON-NLS-1$
}
}
}
}
protected static final String P_VERSION = "version"; //$NON-NLS-1$
protected static final String P_RESOLVE = "resolve"; //$NON-NLS-1$
public static final String A_LEFT = "left"; //$NON-NLS-1$
public static final String A_LEFT_SH = "left_sh"; //$NON-NLS-1$
public static final String A_LEFT_SL = "left_sl"; //$NON-NLS-1$
public static final String A_RIGHT = "right"; //$NON-NLS-1$
public static final String A_RIGHT_SH = "right_sh"; //$NON-NLS-1$
public static final String A_RIGHT_SL = "right_sl"; //$NON-NLS-1$
protected static final String C_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
protected static final String C_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
protected static final String C_PREPARE_MAKE_UT = "prepare_make_ut"; //$NON-NLS-1$
protected static final String C_ROUNDABOUT = "roundabout"; //$NON-NLS-1$
protected static final String C_GO_AHEAD = "go_ahead"; //$NON-NLS-1$
protected static final String C_TURN = "turn"; //$NON-NLS-1$
protected static final String C_MAKE_UT = "make_ut"; //$NON-NLS-1$
protected static final String C_PREAMBLE = "preamble"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_DESTINATION = "and_arrive_destination"; //$NON-NLS-1$
protected static final String C_THEN = "then"; //$NON-NLS-1$
protected static final String C_REACHED_DESTINATION = "reached_destination"; //$NON-NLS-1$
protected static final String C_BEAR_LEFT = "bear_left"; //$NON-NLS-1$
protected static final String C_BEAR_RIGHT = "bear_right"; //$NON-NLS-1$
protected static final String C_ROUTE_RECALC = "route_recalc"; //$NON-NLS-1$
protected static final String C_ROUTE_NEW_CALC = "route_new_calc"; //$NON-NLS-1$
protected static final String DELAY_CONST = "delay_"; //$NON-NLS-1$
public class CommandBuilder {
private boolean alreadyExecuted = false;
private List<Struct> listStruct = new ArrayList<Struct>();
public CommandBuilder(){
this(true);
}
public CommandBuilder(boolean preamble) {
if (preamble) {
addCommand(C_PREAMBLE);
}
}
private void checkState(){
if(alreadyExecuted){
throw new IllegalArgumentException();
}
}
private CommandBuilder addCommand(String name, Object... args){
checkState();
Term[] list = new Term[args.length];
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if(o instanceof java.lang.Number){
if(o instanceof java.lang.Double){
list[i] = new alice.tuprolog.Double((Double) o);
} else if(o instanceof java.lang.Float){
list[i] = new alice.tuprolog.Float((Float) o);
} else if(o instanceof java.lang.Long){
list[i] = new alice.tuprolog.Long((Long) o);
} else {
list[i] = new alice.tuprolog.Int(((java.lang.Number)o).intValue());
}
} else if(o instanceof String){
list[i] = new Struct((String) o);
}
if(list[i]== null){
throw new NullPointerException(name +" " + o); //$NON-NLS-1$
}
}
Struct struct = new Struct(name, list);
if(log.isDebugEnabled()){
log.debug("Adding command : " + name + " " + Arrays.toString(args)); //$NON-NLS-1$ //$NON-NLS-2$
}
listStruct.add(struct);
return this;
}
public CommandBuilder goAhead(){
return addCommand(C_GO_AHEAD);
}
public CommandBuilder goAhead(double dist){
return addCommand(C_GO_AHEAD, dist);
}
public CommandBuilder makeUT(){
return addCommand(C_MAKE_UT);
}
public CommandBuilder makeUT(double dist){
return addCommand(C_MAKE_UT, dist);
}
public CommandBuilder prepareMakeUT(double dist){
return addCommand(C_PREPARE_MAKE_UT, dist);
}
public CommandBuilder turn(String param){
return addCommand(C_TURN, param);
}
public CommandBuilder turn(String param, double dist){
return addCommand(C_TURN, param, dist);
}
/**
*
* @param param A_LEFT, A_RIGHT, ...
* @param dist
* @return
*/
public CommandBuilder prepareTurn(String param, double dist){
return addCommand(C_PREPARE_TURN, param, dist);
}
public CommandBuilder prepareRoundAbout(double dist){
return addCommand(C_PREPARE_ROUNDABOUT, dist);
}
public CommandBuilder roundAbout(double dist, double angle, int exit){
return addCommand(C_ROUNDABOUT, dist, angle, exit);
}
public CommandBuilder roundAbout(double angle, int exit){
return addCommand(C_ROUNDABOUT, angle, exit);
}
public CommandBuilder andArriveAtDestination(){
return addCommand(C_AND_ARRIVE_DESTINATION);
}
public CommandBuilder arrivedAtDestination(){
return addCommand(C_REACHED_DESTINATION);
}
public CommandBuilder bearLeft(){
return addCommand(C_BEAR_LEFT);
}
public CommandBuilder bearRight(){
return addCommand(C_BEAR_RIGHT);
}
public CommandBuilder then(){
return addCommand(C_THEN);
}
public CommandBuilder newRouteCalculated(double dist){
return addCommand(C_ROUTE_NEW_CALC, dist);
}
public CommandBuilder routeRecalculated(double dist){
return addCommand(C_ROUTE_RECALC, dist);
}
public void play(){
CommandPlayer.this.playCommands(this);
}
protected List<String> execute(){
alreadyExecuted = true;
return CommandPlayer.this.execute(listStruct);
}
}
}
package net.osmand.plus.voice;
import java.util.List;
import alice.tuprolog.Struct;
public interface CommandPlayer {
public abstract String getCurrentVoice();
public abstract CommandBuilder newCommandBuilder();
public abstract void playCommands(CommandBuilder builder);
public abstract void clear();
public abstract List<String> execute(List<Struct> listStruct);
}

View file

@ -0,0 +1,20 @@
package net.osmand.plus.voice;
/**
* Exception on CommandPlayer
*
* @author Pavol Zibrita <pavol.zibrita@gmail.com>
*/
public class CommandPlayerException extends Exception {
private static final long serialVersionUID = 8413902962574061832L;
private final String error;
public CommandPlayerException(String error) {
this.error = error;
}
public String getError() {
return error;
}
}

View file

@ -0,0 +1,31 @@
package net.osmand.plus.voice;
import java.io.File;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.activities.OsmandApplication;
import android.content.Context;
public class CommandPlayerFactory {
public static CommandPlayer createCommandPlayer(String voiceProvider, OsmandApplication osmandApplication, Context ctx)
throws CommandPlayerException
{
if (voiceProvider != null){
File parent = OsmandSettings.getOsmandSettings(ctx).extendOsmandPath(ResourceManager.VOICE_PATH);
File voiceDir = new File(parent, voiceProvider);
if(!voiceDir.exists()){
throw new CommandPlayerException(ctx.getString(R.string.voice_data_unavailable));
}
if (MediaCommandPlayerImpl.isMyData(voiceDir)) {
return new MediaCommandPlayerImpl(osmandApplication, voiceProvider);
} else if (TTSCommandPlayerImpl.isMyData(voiceDir)) {
return new TTSCommandPlayerImpl(osmandApplication, voiceProvider);
}
throw new CommandPlayerException(ctx.getString(R.string.voice_data_not_supported));
}
return null;
}
}

View file

@ -0,0 +1,115 @@
package net.osmand.plus.voice;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.osmand.LogUtil;
import org.apache.commons.logging.Log;
import android.content.Context;
import android.media.MediaPlayer;
/**
* That class represents command player.
* It gets commands from input, analyze what files should be played and play
* them using media player
*/
public class MediaCommandPlayerImpl extends AbstractPrologCommandPlayer {
private static final String CONFIG_FILE = "_config.p";
private static final Log log = LogUtil.getLog(MediaCommandPlayerImpl.class);
// playing media
private MediaPlayer mediaPlayer;
// indicates that player is ready to play first file
private boolean playNext = true;
private List<String> filesToPlay = Collections.synchronizedList(new ArrayList<String>());
public MediaCommandPlayerImpl(Context ctx, String voiceProvider)
throws CommandPlayerException
{
super(ctx, voiceProvider, CONFIG_FILE);
mediaPlayer = new MediaPlayer();
}
@Override
public void clear() {
super.clear();
mediaPlayer = null;
}
@Override
public void playCommands(CommandBuilder builder){
filesToPlay.addAll(builder.execute());
playQueue();
}
private synchronized void playQueue() {
while (!filesToPlay.isEmpty() && playNext) {
String f = filesToPlay.remove(0);
if (f != null && voiceDir != null) {
boolean exists = false;
// if(voiceZipFile != null){
// ZipEntry entry = voiceZipFile.getEntry(f);
// exists = entry != null;
// voiceZipFile.getInputStream(entry);
//
// } else {
File file = new File(voiceDir, f);
exists = file.exists();
// }
if (exists) {
log.debug("Playing file : " + f); //$NON-NLS-1$
playNext = false;
try {
// Can't play sound file from zip it seams to be impossible only unpack and play!!!
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mediaPlayer = new MediaPlayer();
int sleep = 60;
boolean delay = true;
while (!filesToPlay.isEmpty() && delay) {
delay = filesToPlay.get(0).startsWith(DELAY_CONST);
if (delay) {
String s = filesToPlay.remove(0).substring(DELAY_CONST.length());
try {
sleep += Integer.parseInt(s);
} catch (NumberFormatException e) {
}
}
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
playNext = true;
playQueue();
}
});
mediaPlayer.start();
} catch (Exception e) {
log.error("Error while playing voice command", e); //$NON-NLS-1$
playNext = true;
}
} else {
log.info("Play file not found : " + f); //$NON-NLS-1$
}
}
}
}
public static boolean isMyData(File voiceDir) {
return new File(voiceDir, CONFIG_FILE).exists();
}
}

View file

@ -0,0 +1,39 @@
package net.osmand.plus.voice;
import java.io.File;
import java.util.List;
import net.osmand.plus.activities.InitTTSActivity;
import android.content.Context;
import android.content.Intent;
import android.speech.tts.TextToSpeech;
public class TTSCommandPlayerImpl extends AbstractPrologCommandPlayer {
private static final String CONFIG_FILE = "_ttsconfig.p";
protected TTSCommandPlayerImpl(Context ctx, String voiceProvider) throws CommandPlayerException {
super(ctx, voiceProvider, CONFIG_FILE);
final Intent intent = new Intent(ctx, InitTTSActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
@Override
public void playCommands(CommandBuilder builder) {
if (TTSOsmand.mTts != null) {
final List<String> execute = builder.execute(); //list of strings, the speech text, play it
StringBuilder bld = new StringBuilder();
for (String s : execute) {
bld.append(s).append(' ');
}
TTSOsmand.mTts.speak(bld.toString(), TextToSpeech.QUEUE_ADD, null);
}
}
public static boolean isMyData(File voiceDir) {
return new File(voiceDir, CONFIG_FILE).exists();
}
}

View file

@ -0,0 +1,9 @@
package net.osmand.plus.voice;
import android.speech.tts.TextToSpeech;
public class TTSOsmand {
public static TextToSpeech mTts;
}

View file

@ -0,0 +1,124 @@
:- op('==', xfy, 500).
version(0).
% before each announcement (beep)
preamble - [].
%% TURNS
turn('left', ['turn.ogg', 'left-e.ogg']).
turn('left_sh', ['sharp_left-e.ogg']).
turn('left_sl', ['turn.ogg', 'left-e.ogg']).
turn('right', ['turn.ogg', 'right-e.ogg']).
turn('right_sh', ['sharp_right-e.ogg']).
turn('right_sl', ['turn.ogg', 'right-e.ogg']).
prepare_turn(Turn, Dist) == ['Prepare_to-a.ogg', 'after-m.ogg', delay_450, D, delay_450, M] :-
distance(Dist) == D, turn(Turn, M).
turn(Turn, Dist) == ['after-m.ogg', delay_250, D, delay_250, M] :-
distance(Dist) == D, turn(Turn, M).
turn(Turn) == M :- turn(Turn, M).
prepare_make_ut(Dist) == ['Prepare_to-a.ogg', 'after-m.ogg', delay_300, D, delay_300,'turn_back-e.ogg'] :-
distance(Dist) == D.
prepare_roundabout(Dist) == ['prepare_to-enter.ogg', 'after-m.ogg', delay_300, D] :-
distance(Dist) == D.
make_ut(Dist) == ['after-m.ogg', delay_300, D, delay_300, 'turn_back-e.ogg'] :-
distance(Dist) == D.
make_ut == ['turn_back-e.ogg'].
roundabout(Dist, _Angle, Exit) == ['after-m.ogg', delay_300, D, delay_300, 'enter_the_roundabout-e.ogg', delay_250, 'and_take.ogg',
delay_250, E, 'exit-e.ogg'] :- distance(Dist) == D, nth(Exit, E).
roundabout(_Angle, Exit) == ['taking.ogg', delay_250, E, 'exit-e.ogg'] :- nth(Exit, E).
and_arrive_destination == ['arrive_at_your_destination-e.ogg']. % Miss and?
then == ['then.ogg', delay_350].
reached_destination == ['you_have_reached_your_destination.ogg'].
bear_right == ['keep_right-e.ogg'].
bear_left == ['keep_left-e.ogg'].
route_recalc(_Dist) == []. % ['recalc.ogg']. %nothing to said possibly beep?
route_new_calc(Dist) == ['the_trip_is_more_than.ogg', delay_150, D] :- distance(Dist) == D. % nothing to said possibly beep?
go_ahead(Dist) == ['drive_for-h.ogg', delay_250, D]:- distance(Dist) == D.
go_ahead == ['continue_straight-e.ogg'].
%%
nth(1, '1st.ogg').
nth(2, '2nd.ogg').
nth(3, '3rd.ogg').
nth(4, '4th.ogg').
nth(5, '5th.ogg').
nth(6, '6th.ogg').
nth(7, '7th.ogg').
nth(8, '8th.ogg').
nth(9, '9th.ogg').
nth(10, '10th.ogg').
nth(11, '11th.ogg').
nth(12, '12th.ogg').
nth(13, '13th.ogg').
nth(14, '14th.ogg').
nth(15, '15th.ogg').
nth(16, '16th.ogg').
nth(17, '17th.ogg').
%%% distance measure
distance(Dist) == T :- Dist < 1000, dist(Dist, F), append(F, 'meters-e.ogg',T).
dist(D, ['10.ogg']) :- D < 20, !.
dist(D, ['20.ogg']) :- D < 30, !.
dist(D, ['30.ogg']) :- D < 40, !.
dist(D, ['40.ogg']) :- D < 50, !.
dist(D, ['50.ogg']) :- D < 60, !.
dist(D, ['60.ogg']) :- D < 70, !.
dist(D, ['70.ogg']) :- D < 80, !.
dist(D, ['80.ogg']) :- D < 90, !.
dist(D, ['90.ogg']) :- D < 100, !.
dist(D, ['100.ogg']) :- D < 150, !.
dist(D, ['100_and.ogg', '50.ogg']) :- D < 200, !.
dist(D, ['200.ogg']) :- D < 250, !.
dist(D, ['200_and.ogg', '50.ogg']) :- D < 300, !.
dist(D, ['300.ogg']) :- D < 350, !.
dist(D, ['300_and.ogg', '50.ogg']) :- D < 400, !.
dist(D, ['400.ogg']) :- D < 450, !.
dist(D, ['400_and.ogg', '50.ogg']) :- D < 500, !.
dist(D, ['500.ogg']) :- D < 550, !.
dist(D, ['500_and.ogg', '50.ogg']) :- D < 600, !.
dist(D, ['600.ogg']) :- D < 650, !.
dist(D, ['600_and.ogg', '50.ogg']) :- D < 700, !.
dist(D, ['700.ogg']) :- D < 750, !.
dist(D, ['700_and.ogg', '50.ogg']) :- D < 800, !.
dist(D, ['800.ogg']) :- D < 850, !.
dist(D, ['800_and.ogg', '50.ogg']) :- D < 900, !.
dist(D, ['900.ogg']) :- D < 950, !.
dist(D, ['900_and.ogg', '50.ogg']) :- !.
distance(Dist) == ['more_than.ogg', '1.ogg', 'kilometer-e.ogg'] :- Dist < 1500.
distance(Dist) == ['more_than.ogg', '2.ogg', 'kilometers-e.ogg'] :- Dist < 3000.
distance(Dist) == ['more_than.ogg', '3.ogg', 'kilometers-e.ogg'] :- Dist < 4000.
distance(Dist) == ['more_than.ogg', '4.ogg', 'kilometers-e.ogg'] :- Dist < 5000.
distance(Dist) == ['more_than.ogg', '5.ogg', 'kilometers-e.ogg'] :- Dist < 6000.
distance(Dist) == ['more_than.ogg', '6.ogg', 'kilometers-e.ogg'] :- Dist < 7000.
distance(Dist) == ['more_than.ogg', '7.ogg', 'kilometers-e.ogg'] :- Dist < 8000.
distance(Dist) == ['more_than.ogg', '8.ogg', 'kilometers-e.ogg'] :- Dist < 9000.
distance(Dist) == ['more_than.ogg', '9.ogg', 'kilometers-e.ogg'] :- Dist < 10000.
distance(Dist) == ['more_than.ogg', X, 'kilometers-e.ogg'] :- D is Dist/1000, dist(D, X).
%% resolve command main method
%% if you are familar with Prolog you can input specific to the whole mechanism,
%% by adding exception cases.
flatten(X, Y) :- flatten(X, [], Y), !.
flatten([], Acc, Acc).
flatten([X|Y], Acc, Res):-
flatten(Y, Acc, R), flatten(X, R, Res).
flatten(X, Acc, [X|Acc]).
resolve(X, Y) :- resolve_impl(X,Z), flatten(Z, Y).
resolve_impl([],[]).
resolve_impl([X|Rest], List) :- resolve_impl(Rest, Tail), ((X == L) -> append(L, Tail, List); List = Tail).