L'ultima cosa in sospeso che avevamo, nello studiare lo Speech Recognizing, era il TTS, che credi di avere dimenticato, e adesso io ti propongo una sessione razionale sul TTS, che così, si spera, non dimenticherai mai più in un modo così importante.
Ricordo che la prima cosa nel TTS era una funzione chiamata onInit, ma non ne ricordo né lo scope né il tipo.
Prova a scriverla, magari tentando di dare voce al risultato della ArrayList che è ottenuta da un RecognizerIntent.
Bene, la scrivo nel programma.
No, nulla da fare. Sono costretto a rivederla. Mi sto sentendo male perché sento che il mio apprendimento sembra poco serio, e troppo mnemonico, senza rendermi conto dei costrutti fino in fondo.
Bene, allora partiremo da questa funzione per analizzare la cosa al meglio con gli strumenti della razionalità.
L'elemento fondamentale è istanziare un oggetto della classe TextToSpeech.
Distruggo tutto ciò che ho sul tavolo del laboratorio e costruisco.
public class MainActivity extends AppCompatActivity {
Button button;
TextToSpeech TTS;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button)findViewById(R.id.button);
}
}
Questa è una dichiarazione.Ora devo inizializzare o istanziare la variabile TTS di tipo TextToSpeech.
Lo schema è sempre quello:
TTS=new TextToSpeech();Questo non basta, ottengo una segnalazione di errore.
Che errore?
Cannot resolve constructor.
Bene, a questo punto dobbiamo cercare i costruttori della classe TextToSpeech.
Ecco: il costruttore ha come parametri il context e un'istanza dell'interfaccia TextToSpeech.onInitListener.
Questa verrebbe chiamata quando il motore di sintesi vocale è stato inizializzato.
Ma si tratta di un'interfaccia che ha metodi che vanno implementati, per cui scrivere soltanto
TTS=new TextToSpeech(this,new TextToSpeech.OnInitListener());dà un messaggio di errore che dice "OnInitListener è astratta, non può essere istanziata".
L'interfaccia ha metodi che devono essere implementati: con Alt e Invio in Android Studio si ottiene la guida all'implementazione del metodo onInit.
TTS=new TextToSpeech(this, new TextToSpeech.OnInitListener() { @Override public void onInit(int i) { } });Bene. Come si implementa il metodo?
Android Studio mi dà come parametro di onInit un int chiamato i, mentre Eclipse mi dava un int chiamato status.
Il concetto è lo stesso: bisogna in qualche modo vedere se questo status ha avuto successo, ossia se il motore è stato inizializzato correttamente, credo.
Esiste una costante di TextToSpeech che si chiama TextToSpeech.SUCCESS, e appunto la condizione essenziale per procedere a questo punto, trattandosi dell'avvio del motore del TextToSpeech, è che questo status, o "i" che dir si voglia, sia uguale a questa costante SUCCESS, ossia abbia avuto successo.
In tal caso si può procedere a settare il linguaggio come italiano.
La sintassi Locale.ITALIAN è la stessa che per il RecognizerIntent.
A questo punto forse dovrei essere in grado di fare il Mandala e riscrivere tutto.
TTS=new TextToSpeech(this,new TextToSpeech.OnInitListener(){ @Override public void onInit(int i) { if(i==TextToSpeech.SUCCESS){ TTS.setLanguage(Locale.ITALIAN); } } });Esatto!
Saresti capace di implementare l'interfaccia in modo non anonimo e poi porre l'oggetto che implementa l'interfaccia come parametro nell'istanziazione di TTS?
Proviamo...
TextToSpeech.OnInitListener onInitListener=new TextToSpeech.OnInitListener(){ @Override public void onInit(int i) { if(i==TextToSpeech.SUCCESS){ TTS.setLanguage(Locale.ITALIAN); } } }; TTS=new TextToSpeech(this,onInitListener);Messaggi di errore non ne vedo. E' possibile, però, che vi sia qualche NullPointer dato che TTS non è ancora stato istanziato quando si setta il linguaggio? Non credo, però: è un listener non "gira" prima dell'istanziazione di TTS.
Proviamo.
Ci aggiungo il comando che lo fa parlare:
TextToSpeech.OnInitListener onInitListener=new TextToSpeech.OnInitListener(){ @Override public void onInit(int i) { if(i==TextToSpeech.SUCCESS){ TTS.setLanguage(Locale.ITALIAN); } } }; TTS=new TextToSpeech(this,onInitListener); button.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { TTS.speak("Ciao, bello",TextToSpeech.QUEUE_FLUSH,null); } });e vediamo.
(la sintassi del comando speak() va revisionata).
Okay, funziona anche con questa sintassi.
Cosa significa quel QUEUE_FLUSH, e quel null?
Non avere paura, si tratta solo di fare due excursus sulla documentazione ufficiale e, se non sufficiente, su altro materiale presente in rete.
Posso tornare a vederlo successivamente, fra qualche minuto?
E sia... hai trovato degli sviluppi da approfondire e hai paura. E se invece decidessimo di vincere la paura e farlo adesso? Se vuoi, accenditi la sigaretta adesso qui, dato che lo puoi fare, questo te lo concedo.
E sia...
Oltre al testo da dire, abbiamo due possibili modalità QUEUE MODE: una QUEUE_FLUSH, che, credo, significhi che le successive frasi vengono a sostituire quelle attuali nella fila per la sintesi e l'output vocale, mentre QUEUE_ADD significherebbe che vengono sommate a quelle attuali.
La cosa richiederebbe una verifica sperimentale per essere ben compresa.
La facciamo?
E dai, facciamola.
Sì! Premendo ripetutamente il tasto che "parla", se è attivo QUEUE_FLUSH la frase viene detta una volta sola, in quanto il nuovo testo rimpiazza il precedente, mentre se è attivo QUEUE_ADD la frase viene tenuta memorizzata insieme a tutte le successive, e vengono dette tutte una appresso all'altra.
Questa sintassi è deprecata nelle API più nuove.
La sintassi corretta sarebbe questa:
TTS.speak("Ciao, bello",TextToSpeech.QUEUE_FLUSH,null,null);che però, dal momento in cui la mia applicazione si estende anche all'API 18, non mi viene concessa, in quanto la forma precedente risulta deprecata dall'API 21 in poi.
Possiamo accontentarci così. Non è bene poi lasciarsi prendere dalle smanie e voler approfondire eccessivamente e in modo convulso. E' un'altra faccia della paura, paura di considerare il proprio apprendimento poco valido.
Questa paura può condurti o ad evitare la programmazione per non incorrere in cose difficili che ti facciano autogiudicare male, o a voler approfondire tutto convulsamente e nevroticamente, per evitare di autogiudicarsi male.
Il necessario verrà.
Facciamo un Mandala finale.
public class MainActivity extends AppCompatActivity { Button button; TextToSpeech TTS; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=(Button)findViewById(R.id.button); TTS=new TextToSpeech(this, new TextToSpeech.OnInitListener() { @Override public void onInit(int i) { if(i==TextToSpeech.SUCCESS){ TTS.setLanguage(Locale.ITALIAN); } } }); button.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View view) { TTS.speak("Questo è il testo",TextToSpeech.QUEUE_FLUSH,null); } }); } }Funziona!
Ora un mega-Mandala che riconosce il testo parlato e lo replica con il sintetizzatore vocale.
public class MainActivity extends AppCompatActivity { Button button; TextToSpeech TTS; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=(Button)findViewById(R.id.button); TTS=new TextToSpeech(this,new TextToSpeech.OnInitListener(){ @Override public void onInit(int i) { if(i==TextToSpeech.SUCCESS){ TTS.setLanguage(Locale.ITALIAN); } } }); button.setOnClickListener(new Button.OnClickListener(){ @Override public void onClick(View view) { Intent intent=new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.ITALIAN); intent.putExtra(RecognizerIntent.EXTRA_PROMPT,"PARLA ORA"); startActivityForResult(intent,0); } }); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data){ if(resultCode==RESULT_OK){ ArrayList<String> lista=data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); String testo=lista.get(0); TTS.speak(testo,TextToSpeech.QUEUE_FLUSH,null); } } }Funziona alla perfezione!
Nessun commento:
Posta un commento