Erweiterung der Android-Processing-VR-Funktionalität um den Befehl "sprich(String)"
(EN google-translate)
(PL google-translate)
Der Sprachsynthesizer wurde bereits mehrfach in vorangehend besprochenen Sketches benutzt. Nun geht es mehr darum, ihn sinnvoll zu modularisieren. Insbesondere gilt es dabei, die Komplexität der zugehörigen Programmstruktur für den "Benutzer-Programmierer" zu verbergen, die insbesondere darin besteht...
|
Lazy Binding
Nicht in jedem Programm wird die Sprachsynthese benötigt werden. Andererseits möchte man für die einfache Benutzung nicht gerne noch einen Konstruktor bei Bedarf aufrufen müssen.
Eine Lösung für dieses Problem stellt die Verwendung des s.g. Lazy-Binding dar: Programmstrukturen, die nicht immer benötigt werden, werden erst initialisiert und geladen, wenn sie das erste mal benutzt werden sollen. Im konkreten Fall kann mit Aufrufen der Funktion "sprich(String)" jedesmal geprüft werden, ob das Sprach-Synthesizer-Objekt "null" ist und ggf. der Konstruktor aufgerufen werden.
Umsetzung
In der folgenden Realisierung kann nach Übernahme des Tabs "Zusatz" in einen beliebigen Sketch (für VR-Android) im Hauptprogramm der Sprachsynthesizer einfach durch Verwendung der Funktion sprich("Mein Text"); verwendet werden:
import processing.vr.*; //ACHTUNG: //Android->VR anhaken PMatrix3D eyeMat = new PMatrix3D(); String zeichen = "ABCDEFGHIJKLMNOPQRSTUVWXZ"; int RESTZEIT = 0; String[] AUSWAHL = {"1","2","3"}; int inx=0; void setup() { fullScreen(MONO); } void draw() { //Standardeinstellungen für unser Arbeiten: background(0); getEyeMatrix(eyeMat); //Kameramatrix auslesen translate(eyeMat.m03, eyeMat.m13, eyeMat.m23); //Welt in Koordinatenursprung von Kamera setzen. lights(); float ez_x = eyeMat.m02; //Einheitsvektor der aktuellen Blickrichtung // float ez_y = -eyeMat.m12; float ez_y = eyeMat.m12; float ez_z = eyeMat.m22; //ENDE Standardeinstellungen für unser Arbeiten: //Buchstaben auf "Platten" zeichnen: textSize(64); for(int i=0;i<zeichen.length();i++) { pushMatrix(); float z = -500.0f; float y = - 200 + (i/5)*100; float x = 100*(i%5) - 200; //Nähe zum Zielkreis: //1) Einheitsvektor bilden: float laenge = sqrt(x*x+y*y+z*z); float xx=x/laenge; float yy=y/laenge; float zz=z/laenge; //2) Skalarprodukt mit Blickrichtung (ez) float sk = xx*ez_x + yy*ez_y + zz*ez_z; if(sk>0.99f && RESTZEIT==0) { AUSWAHL[inx]=zeichen.substring(i,i+1); inx++; inx%=AUSWAHL.length; if(AUSWAHL[0].equals(AUSWAHL[1]) && AUSWAHL[1].equals(AUSWAHL[2])) { sprich(AUSWAHL[0]); AUSWAHL[0] ="1"; AUSWAHL[1] ="2"; AUSWAHL[2] ="3"; } RESTZEIT = 30; } translate(x,y,z); noStroke(); fill(0,255,0); text(zeichen.substring(i,i+1),-20,20); popMatrix(); } //Zielkreis zeichnen eye(); //Transformation realtiv zur Kamera translate(0, 0, 95); //Zielkreis relativ zur Kamera zeichnen noFill(); stroke(255,0,0); ellipse(0, 0, 10, 10); if(RESTZEIT>0) RESTZEIT--; }
Code 0-1: Sprich.pde
//TTS: import android.speech.tts.TextToSpeech; import java.util.Locale; import java.util.Set; import android.media.AudioManager; import android.content.Context; TTS tts = null; public void sprich(String text) { if(tts==null) { tts = new TTS(); tts.setzeSpechgeschwindigkeit(1.0f); tts.setzeStimmhoehe(1.0f); tts.setzeLautstaerke(0.8f); } if(tts!=null) { tts.sprich(text); } } public class TTS implements Runnable { ArrayList<String> warteschlange = new ArrayList<String>(); TextToSpeech tts; AudioManager audio; int currentVolume; int maxVolume; public void setzeSpechgeschwindigkeit(float s) { tts.setSpeechRate(s); } public void setzeStimmhoehe(float h) { tts.setSpeechRate(h); } public void setzeLautstaerke(float ls) { if(ls<0.0f) ls=0.0f; if(ls>1.0f) ls=1.0f; int LAUT = (int) (maxVolume*ls); audio.setStreamVolume(AudioManager.STREAM_MUSIC, LAUT, 0); } public void run() { while(true) { if(tts!=null && warteschlange.size()>0 && !tts.isSpeaking()) { String text = warteschlange.get(0); warteschlange.remove(0); tts.speak(text, TextToSpeech.QUEUE_FLUSH, null); } try { Thread.sleep(100); } catch(Exception e) { } } } public void sprich(String text) { warteschlange.add(text); } public TTS() { //NEU: getActivity(). ab Proc. 3! tts=new TextToSpeech(getActivity().getApplicationContext(), new TextToSpeech.OnInitListener() { //@Override public void onInit(int status) { if(status != TextToSpeech.ERROR) { tts.setLanguage(Locale.GERMAN); } } }); audio = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); //NEU: getActivity(). ab Proc. 3! currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC); maxVolume = audio.getStreamMaxVolume(AudioManager.STREAM_MUSIC); //eigenen Thread starten: (new Thread(this)).start(); } }
Code 0-2: Zusatz.pde